(Это упрощенная версия моего первоначального вопроса)
У меня есть несколько потоков, которые пишут в сокет asio. Это, кажется, работает очень хорошо, без проблем.
В документации говорится, что общий сокет не является потокобезопасным (здесь, путь вниз внизу), поэтому мне интересно, следует ли мне защищать сокет с мьютексом или что-то в этом роде.
Этот question настаивает на необходимости защиты, но не дает никаких советов о том, как это сделать.
Все ответы на мой оригинальный вопрос также настаивали на том, что я делаю опасно, и больше всего призывал меня заменить мои записи на async_writes или даже более сложные вещи. Тем не менее, я неохотно это делаю, так как это усложнит код, который уже работает, и никто из ответчиков не убедил меня, что они знают, о чем они говорят, - они, казалось, прочитали ту же документацию, что и я, и догадывались, так же как я был.
Итак, я написал простую программу для стресс-тестирования записи в общий сокет из двух потоков.
Вот сервер, который просто выписывает все, что получает от клиента
int main()
{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3001));
tcp::socket socket(io_service);
acceptor.accept(socket);
for (;;)
{
char mybuffer[1256];
int len = socket.read_some(boost::asio::buffer(mybuffer,1256));
mybuffer[len] = '\0';
std::cout << mybuffer;
std::cout.flush();
}
return 0;
}
Вот клиент, который создает два потока, которые записывают в общий сокет так быстро, как могут
boost::asio::ip::tcp::socket * psocket;
void speaker1()
{
string msg("speaker1: hello, server, how are you running?\n");
for( int k = 0; k < 1000; k++ ) {
boost::asio::write(
*psocket,boost::asio::buffer(msg,msg.length()));
}
}
void speaker2()
{
string msg("speaker2: hello, server, how are you running?\n");
for( int k = 0; k < 1000; k++ ) {
boost::asio::write(
*psocket,boost::asio::buffer(msg,msg.length()));
}
}
int main(int argc, char* argv[])
{
boost::asio::io_service io_service;
// connect to server
tcp::resolver resolver(io_service);
tcp::resolver::query query("localhost", "3001");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
psocket = new tcp::socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
psocket->close();
psocket->connect(*endpoint_iterator++, error);
}
boost::thread t1( speaker1 );
boost::thread t2( speaker2 );
Sleep(50000);
}
Это работает! Отлично, насколько я могу судить. Клиент не падает. Сообщения поступают на сервер без искажений. Они обычно приходят попеременно, по одному от каждой нити. Иногда один поток получает два или три сообщения перед другим, но я не думаю, что это проблема, если нет никаких искажений и все сообщения поступают.
Мое заключение: сокет не может быть потокобезопасным в некотором теоретическом смысле, но так сложно заставить его потерпеть неудачу, что я не буду беспокоиться об этом.