문제

나는 boost.asio를 사용하여 서버를 작성하고 있습니다. 각 연결에 대한 버퍼를 읽고 쓰고 비동기식 읽기/쓰기 기능을 사용합니다 (async_write_some / async_read_some).

읽기 버퍼와 함께 async_read_some, 문제 없다. 그냥 호출 async_read_some 읽기 버퍼는 읽기 핸들러에서만 읽히기 때문에 기능은 괜찮습니다 (일반적으로 같은 스레드에서는).

그러나 여러 스레드에서 쓰기 버퍼에 액세스해야하므로 수정하려면 잠겨 있어야합니다.

첫 번째 질문!

쓰기 버퍼의 잠금을 피할 수있는 방법이 있습니까?

내 자신의 패킷을 스택 버퍼에 쓰고 쓰기 버퍼에 복사합니다. 그런 다음 전화하십시오 async_write_some 패킷을 보내는 기능. 이런 식으로, 두 개의 패킷을 연쇄로 보내면 괜찮습니까? async_write_some 두 번 기능 하시겠습니까?

두 번째 질문!

소켓 프로그래밍에서 비동기 쓰기의 일반적인 방법은 무엇입니까?

읽어 주셔서 감사합니다.

도움이 되었습니까?

해결책

답변 #1 :

잠금이 실행 가능한 접근법이라는 것이 맞습니다. 그러나이 모든 것을 수행하는 훨씬 간단한 방법이 있습니다. 부스트 strand. 스트랜드를 사용하여 래핑 한 콜백은 콜백을 실행하는 스레드에 관계없이 직렬화되고 보장됩니다. 기본적으로, 그것은 당신을 위해 모든 잠금을 처리합니다.

이것은 당신이 원하는만큼 많은 작가를 가질 수 있고, 그들이 모두가 싸우는 경우 같은 가닥 (따라서 모든 작가들 사이에서 단일 가닥을 공유하십시오) 그들은 일련의 실행을 수행합니다. 조심해야 할 한 가지는 모든 글을 수행하기 위해 메모리에서 동일한 실제 버퍼를 사용하려고하지 않도록하는 것입니다. 예를 들어, 이것은 피해야 할 것입니다.

char buffer_to_write[256];  // shared among threads

/* ... in thread 1 ... */
memcpy(buffer_to_write, packet_1, std::min(sizeof(packet_1), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

/* ... in thread 2 ... */
memcpy(buffer_to_write, packet_2, std::min(sizeof(packet_2), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

거기에서 실제 쓰기 버퍼를 공유하고 있습니다 (buffer_to_write). 대신 이런 일을했다면 괜찮을 것입니다.

/* A utility class that you can use */
class PacketWriter
{
private:
  typedef std::vector<char>  buffer_type;

  static void WriteIsComplete(boost::shared_ptr<buffer_type> op_buffer, const boost::system::error_code& error, std::size_t bytes_transferred)
  {
    // Handle your write completion here
  }

public:
  template<class IO>
  static bool WritePacket(const std::vector<char>& packet_data, IO& asio_object)
  {
    boost::shared_ptr<buffer_type> op_buffer(new buffer_type(packet_data));

    if (!op_buffer)
    {
      return (false);
    }

    asio_object.async_write_some(boost::asio::buffer(*op_buffer), boost::bind(&PacketWriter::WriteIsComplete, op_buffer, boost::asio::placeholder::error, boost::asio::placeholder::bytes_transferred));
  }
};

/* ... in thread 1 ... */
PacketWriter::WritePacket(packet_1, my_socket);

/* ... in thread 2 ... */
PacketWriter::WritePacket(packet_2, my_socket);

여기서 스트랜드를 WritePacket에 전달하면 도움이됩니다. 그래도 아이디어를 얻습니다.

답변 #2 :

나는 당신이 이미 아주 좋은 접근 방식을 취하고 있다고 생각합니다. 내가 제공 할 제안 중 하나는 사용하는 것입니다 async_write 대신에 async_write_some 콜백이 호출되기 전에 전체 버퍼가 작성됩니다.

다른 팁

죄송하지만 두 가지 선택이 있습니다.

  1. 잠금 장치로 쓰기 문을 세리어링하거나 대기열에서 요청을 읽는 별도의 라이터 스레드를 더 잘 시작하면 다른 스레드는 너무 많은 경합없이 큐의 요청을 쌓을 수 있습니다 (일부 뮤 테이징이 필요합니다).

  2. 각 작문 스레드에게 자체 소켓을 제공하십시오! 와이어의 다른 쪽 끝에있는 프로그램이이를 지원할 수있는 경우 실제로 더 나은 솔루션입니다.

수정을 대기하고 쓰기 핸들러의 데이터에서 수행 할 수 있습니다.

네트워크는 아마도 파이프의 가장 느린 부분 일 것입니다 (수정이 계산 비용이 많이 들지 않는다고 가정함에 따라 소켓 레이어가 이전 데이터를 전송하는 동안 모드를 수행 할 수 있습니다.

Connect/Disternect 빈번한 많은 클라이언트를 처리하는 경우 IO 완료 포트 또는 이와 유사한 메커니즘을 살펴보십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top