简体   繁体   English

使用websocketpp库在多线程程序中为endpoint.listen()创建单独的增强线程

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

I am trying to integrate a websocketpp server into a multithreaded project. 我正在尝试将websocketpp服务器集成到多线程项目中。 Everything works fine in a single thread approach, but I encountered a problem when creating a separate boost::thread for endpoint.listen() that would run in the background (so it does not disrupt the execution of the main thread). 一切都在单线程方法中运行良好,但是在为Endpoint.listen()创建单独的boost :: thread时会在后台运行时遇到问题(因此不会中断主线程的执行)。 I have tried the code with Boost v1.46.1 and v1.50.0 on Ubuntu 12.04 64-bit with the newest build of websocketpp. 我已经在带有最新版本的websocketpp的Ubuntu 12.04 64位上使用Boost v1.46.1和v1.50.0尝试了该代码。 Below is a code sample and an explanation of my approach. 下面是一个代码示例和我的方法的说明。

#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;

}

If I compile the code with ptr->join(); 如果我用ptr-> join()编译代码 the listening thread works fine, but it makes the main thread sleep. 侦听线程工作正常,但使主线程进入睡眠状态。 If I leave ptr->join() out and let the listening thread run in background, I encounter an error after the thread creation: 如果我省略ptr-> join()并让侦听线程在后台运行,则在创建线程后会遇到错误:

/usr/local/boost_1_50_0/libbin/include/boost/thread/pthread/recursive_mutex.hpp:105: void boost::recursive_mutex::lock(): Assertion `!pthread_mutex_lock(&m)' failed. /usr/local/boost_1_50_0/libbin/include/boost/thread/pthread/recursive_mutex.hpp:105:void boost :: recursive_mutex :: lock():断言`!pthread_mutex_lock(&m)'失败。

I'm not very experienced with threading or boost threads, and quite new with websocketpp, so I'm not sure if I'm doing something wrong here. 我对线程或增强线程的经验不是很丰富,对于websocketpp来说还不是很新,所以我不确定在这里是否做错了什么。 If there are any better (and working) ways to tackle this issue, I would love to see some examples. 如果有解决此问题的更好(可行)方法,我希望看到一些示例。 I have been trying to figure out this problem for a long time now, so any help would be priceless. 我已经很长时间试图解决这个问题了,所以任何帮助都是无价的。 Thanks in advance! 提前致谢!

Check out also: gdb stacktrace and valgrind results 另请检出: gdb stacktracevalgrind结果

Edit: The "while(true)" in the code sample is there just to simulate the processing in the main thread. 编辑:代码示例中的“ while(true)”仅用于模拟主线程中的处理。 I'm integrating a websocket server in a big project that has different types of socket connections, events, data processing, client synchronization etc. running in the background. 我正在将Websocket服务器集成到一个大型项目中,该项目在后台运行不同类型的套接字连接,事件,数据处理,客户端同步等。 The websocket connection provides just another way to connect to the server using a web client instead a native one. Websocket连接提供了另一种使用Web客户端而不是本机客户端连接到服务器的方法。 The main thread creates all the necessary stuff, but I can't really affect in which order they are created, so the websocket server must be started in its own thread. 主线程会创建所有必要的内容,但是我不能真正影响它们的创建顺序,因此websocket服务器必须在其自己的线程中启动。

You create all the objects within the scope of try/catch. 您在try / catch范围内创建所有对象。 When you leave this scope, these objects get destroyed. 当您离开此范围时,这些对象将被销毁。

So, either move the object definitions out of try/catch, or move while(true) loop into it. 因此,可以将对象定义移出try / catch,或将while(true)循环移入其中。

Why are you creating the boost::thread on the heap, when it could be on the stack? 为什么要在堆上创建boost::thread时将其放在堆栈上?

You don't need to use boost::bind with boost::thread , so it should be simply: 您不需要将boost::bindboost::thread boost::bind使用,因此它应该很简单:

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

Much simpler, no? 简单得多,不是吗?

As for your program's behaviour. 至于您程序的行为。 If you call ptr->join() there then the main thread waits for the other thread to finish, which never happens, so of course it sleeps. 如果您在其中调用ptr->join() ,那么主线程将等待另一个线程完成,这永远不会发生,因此它会休眠。 If you don't join it then ptr and echo_endpoint and h all go out of scope. 如果不加入,则ptrecho_endpoint以及h都超出范围。 The other thread will then be trying to use objects which no longer exist. 然后另一个线程将尝试使用不再存在的对象。

As @IgorR. 作为@IgorR。 said , you should put the while loop inside the try-catch block, so the work in the main loop can happen before the other thread and the objects it uses go out of scope. ,您应该将while循环放在try-catch块内,这样主循环中的工作可以其他线程及其使用的对象超出范围之前进行。

From Boost 1.50 the boost::thread destructor matches the behaviour of std::thread ie it calls terminate() if the thread is joinable when its destructor runs. 从Boost 1.50开始, boost::thread析构函数与std::thread的行为匹配,即,如果线程在其析构函数运行时是可连接的,它将调用terminate() This is to prevent the sort of error you have, where the thread continues running even though the boost::thread handle referring to it and other stack objects no longer exist. 这是为了防止出现这种错误,即使引用该线程的boost::thread句柄和其他堆栈对象不再存在,该线程也继续运行。 If you want it to keep running you must detach it explicitly (but in your program that would still be wrong, because the echo_endpoint and h objects would still cease to exist and the thread would still try to use them.) So before a boost::thread object goes out of scope you should either join it or detach it. 如果希望它继续运行,则必须显式detach它(但是在您的程序中这仍然是错误的,因为echo_endpointh对象将仍然不存在,并且线程仍将尝试使用它们。)因此,在进行boost::thread之前boost::thread对象超出范围,您应该joindetach它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM