来自 boost 的 udp 服务器不适用于多线程,但仅在主线程上工作

Udp server from boost not working on multithreading, but work only on the main thread

本文关键字:线程 工作 多线程 boost udp 服务器 适用于 不适用 来自      更新时间:2023-10-16

我得到了一个带有 boost::asio 的异步 udp 服务器 但问题是: 如果我在线程上启动它,服务器将无法工作 但是如果我在主线程上启动它(用服务阻止),它就可以工作了......

我尝试用叉子做,但不能工作

class Server {
private:
boost::asio::io_service _IO_service;
boost::shared_ptr<boost::asio::ip::udp::socket> _My_socket;
boost::asio::ip::udp::endpoint _His_endpoint;
boost::array<char, 1000> _My_Buffer;
private:
void Handle_send(const boost::system::error_code& error, size_t size, std::string msg) {
//do stuff
};
void start_send(std::string msg) {
_My_socket->async_send_to(boost::asio::buffer(msg), _His_endpoint,
boost::bind(&Server::Handle_send, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, msg));
};
void Handle_receive(const boost::system::error_code& error, size_t size) {
//do stuff
};
void start_receive(void) {
_My_socket->async_receive_from(
boost::asio::buffer(_My_Buffer), _His_endpoint,
boost::bind(&Server::Handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
public:
Server(int port):
_IO_service(),
_My_socket(boost::make_shared<boost::asio::ip::udp::socket>(_IO_service, 
boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)))
{
start_receive();
};
void Launch() {
_IO_service.run();
};
};

目标是在后台调用服务器::启动。

首先,您在start_send中有未定义的行为。

async_send_to立即返回,因此当start_send返回时,作为局部变量msg将被销毁。调用async_send_to时,必须确保在异步操作完成之前不会销毁msg。文档中描述的内容 -

尽管可以根据需要复制缓冲区对象,但所有权 底层内存块由调用方保留,调用方必须保证它们在调用处理程序之前保持有效

您可以通过多种方式解决它,最简单的方法是使用字符串作为数据成员(作为发送数据的缓冲区):

class Server {
//..
std::string _M_toSendBuffer;
// 
void start_send(std::string msg) {
_M_toSend = msg; // store msg into buffer for sending
_My_socket->async_send_to(boost::asio::buffer(_M_toSend), _His_endpoint,
boost::bind(&Server::Handle_send, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, 
_M_toSend));
};

另一种解决方案是将msg包装到智能指针中以延长其生命周期:

void Handle_send(const boost::system::error_code& error, size_t size, 
boost::shared_ptr<std::string> msg) {
//do stuff
};
void start_send(std::string msg) {
boost::shared_ptr<std::string> msg2 = boost::make_shared<std::string>(msg); // [1]
_My_socket->async_send_to(boost::asio::buffer(*msg2), _His_endpoint,
boost::bind(&Server::Handle_send, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, 
msg2)); // [2]
};

在 [1] 行中,我们创建shared_ptr它获取msg内容,然后在 [2] 行中,当调用bind时,shared_ptr的引用计数器会增加,因此字符串生存期延长,并在调用处理程序后销毁。


关于您基于线程的不工作版本。您没有显示调用Launch的代码,但也许您只是没有加入此线程?

Server s(3456);
boost::thread th(&Server::Launch,&s);
th.join(); // are you calling this line?

或者也许您的代码在 UB 中不起作用start_send.