在我們的應用程序中,我們使用Boost庫(和ASIO進行網絡通信)。最近,我們發現如果我們通過同一套接口從不同線程發送數據,我們的客戶端應用程序正在接收垃圾數據。從不同線程寫入boost :: asio socket
小試,以突出的問題:
#include <stdio.h>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
void send_routine(boost::shared_ptr<boost::asio::ip::tcp::socket> s, char c)
{
std::vector<char> data(15000, c);
data.push_back('\n');
for (int i=0; i<1000; i++)
boost::asio::write(*s, boost::asio::buffer(&data[0], data.size()));
}
int main()
{
using namespace boost::asio;
using namespace boost::asio::ip;
try {
io_service io_service;
io_service::work work(io_service);
const char* host = "localhost";
const char* service_name = "18000";
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), host, service_name);
tcp::resolver::iterator iterator = resolver.resolve(query);
auto socket = boost::shared_ptr<tcp::socket>(new tcp::socket(io_service));
socket->connect(*iterator);
boost::thread t1(send_routine, socket, 'A');
boost::thread t2(send_routine, socket, 'B');
boost::thread t3(send_routine, socket, 'C');
t1.join();
t2.join();
t3.join();
}
catch (std::exception& e) {
printf("FAIL: %s\n", e.what());
}
return 0;
}
所以,我們在這裏創建插座,連接到localhost:18000
並啓動3個線程將寫入套接字。
在不同的終端窗口中,我運行了nc -l -p 18000 | tee out.txt | sort | uniq | wc -l
。我期望3
作爲輸出,但它會在網絡流中返回多於100個「不同的字符串」(因此數據已損壞)。但它適用於小緩衝區大小(例如,如果我們將15000
更改爲80
)。
所以,問題是:這是ASIO庫的正確行爲嗎?另一個:如何解決它?我應該在我的send_routine
函數中使用mutex
(還是有另一種解決方案)?
'async_write'不會神奇地讓這個問題消失。不同緩衝區的寫入仍然需要串行發生,即使它是通過異步IO完成的。 – Chad 2012-07-20 15:46:59
'io_service'應該爲你序列化。 – berkus 2014-11-11 17:56:51
async_write由多個async_send組成,沒有進一步的線程安全性(我研究了實現)。所以當從不同的線程使用相同的套接字時它不是線程安全的。 – Databyte 2015-06-07 12:22:16