回答#1:
ロックが実行可能なアプローチであることは正しいですが、これをすべて行うためのはるかに簡単な方法があります。Boostには、ASIOに。と呼ばれる小さな構造がありstrand
ます。ストランドを使用してラップされたコールバックは、どのスレッドがコールバックを実行するかに関係なく、シリアル化され、保証されます。基本的に、それはあなたのためにどんなロックも処理します。
これは、必要な数のライターを持つことができ、それらがすべて同じストランドでラップされている場合(つまり、すべてのライター間で単一のストランドを共有する場合)、それらはシリアルに実行されることを意味します。注意すべきことの1つは、すべての書き込みを実行するためにメモリ内の同じ実際のバッファを使用しようとしていないことを確認することです。たとえば、これは避けるべきことです:
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:
あなたはすでに非常に良いアプローチを取っていると思います。私が提案する1つの提案は、コールバックが呼び出される前にバッファー全体が書き込まれることが保証されるように、async_write
代わりに使用することです。async_write_some