使用websockettpp库在多线程程序中为endpoint.listen()创建一个单独的提升线程

Creating a separate boost thread for endpoint.listen() in a multithreaded program using websocketpp library

本文关键字:一个 单独 线程 创建 websockettpp 程序 多线程 使用 listen endpoint      更新时间:2023-10-16

我正在尝试将websockettpp服务器集成到多线程项目中。在单线程方法中一切都很好,但我在为endpoint.listen()创建单独的boost::thread时遇到了一个问题,该线程将在后台运行(这样它就不会中断主线程的执行)。我已经在Ubuntu 12.04 64位的最新版本websockettpp上尝试了Boost v1.46.1和v1.50.0的代码。下面是一个代码示例和对我的方法的解释。

#include <websocketpp/websocketpp.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <exception>
using websocketpp::server;
class echo_server_handler : public server::handler {
public:
    void on_message(connection_ptr con, message_ptr msg) {
        con->send(msg->get_payload(),msg->get_opcode());
    std::cout << "Got message: " << msg->get_payload() << std::endl;
    }
};

int main(int argc, char* argv[]) {
    unsigned short port = 9002;
    try {       
        server::handler::ptr h(new echo_server_handler());
        server echo_endpoint(h);
        echo_endpoint.alog().unset_level(websocketpp::log::alevel::ALL);
        echo_endpoint.elog().unset_level(websocketpp::log::elevel::ALL);
        echo_endpoint.alog().set_level(websocketpp::log::alevel::CONNECT);
        echo_endpoint.alog().set_level(websocketpp::log::alevel::DISCONNECT);
        echo_endpoint.elog().set_level(websocketpp::log::elevel::RERROR);
        echo_endpoint.elog().set_level(websocketpp::log::elevel::FATAL);
        std::cout << "Starting WebSocket echo server on port " << port << std::endl;
        //Getting pointer to the right function
         void(websocketpp::role::server<websocketpp::server>::*f)(uint16_t,size_t) =
                &websocketpp::role::server<websocketpp::server>::listen;
        std::cout << "Starting WSServer thread... n" << std:endl;
        boost::shared_ptr<boost::thread> ptr(new boost::thread(boost::bind(f, &echo_endpoint, port, 1)));
    //ptr->join();
    } catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
    //Simulating processing in the main thread
    while(true) {std::cout << "Main thread processing..."<<std::endl; sleep(5);}

    return 0;
}

如果我使用ptr->join()编译代码侦听线程工作正常,但它会使主线程休眠。如果我去掉ptr->join(),让监听线程在后台运行,我会在线程创建后遇到一个错误:

/usr/local/browst_1_50_0/libbin/include/browst/thread/phread/recursive_mutex.hpp:105:void boost::recursive_mutex::lock():断言`!pthread_mutex_lock(&m)'失败。

我对线程或boost线程没有太多经验,对websockettpp也很陌生,所以我不确定我是否做错了什么。如果有更好的(有效的)方法来解决这个问题,我很乐意看到一些例子。我已经想办法解决这个问题很长时间了,所以任何帮助都是无价的。提前感谢!

还可以查看:gdb堆叠和valgrind结果

编辑:代码示例中的"while(true)"只是为了模拟主线程中的处理。我正在一个大项目中集成一个websocket服务器,该项目在后台运行不同类型的套接字连接、事件、数据处理、客户端同步等。websocket连接提供了另一种使用web客户端而不是本机客户端连接到服务器的方式。主线程创建所有必要的东西,但我不能真正影响它们的创建顺序,所以websocket服务器必须在自己的线程中启动。

您在try/catch范围内创建所有对象。当您离开此范围时,这些对象将被销毁。

因此,要么将对象定义移出try/catch,要么将while(true)循环移入其中

为什么要在堆上创建boost::thread,而它本可以在堆栈上?

您不需要将boost::bindboost::thread一起使用,所以它应该很简单:

    boost::thread t(f, &echo_endpoint, port, 1);

简单多了,不是吗?

至于你的程序的行为。如果你在那里调用ptr->join(),那么主线程会等待另一个线程完成,这永远不会发生,所以它当然会休眠。如果你不加入它,那么ptrecho_endpointh都会超出范围。然后,另一个线程将尝试使用不再存在的对象。

作为@IgorR。也就是说,你应该把while循环放在try-catch块中,这样主循环中的工作就可以在其他线程和它使用的对象超出范围之前发生。

从Boost 1.50开始,boost::thread析构函数与std::thread的行为相匹配,即如果线程在其析构函数运行时是可联接的,则它调用terminate()。这是为了防止出现这样的错误,即即使引用线程的boost::thread句柄和其他堆栈对象不再存在,线程也会继续运行。如果你想让它继续运行,你必须显式地detach它(但在你的程序中,这仍然是错误的,因为echo_endpointh对象仍然不存在,线程仍然会尝试使用它们。)因此,在boost::thread对象超出范围之前,你应该是join它还是detach