简体   繁体   English

ZMQ recv()即使在上下文终止后仍会阻塞

[英]ZMQ recv() is blocking even after the context was terminated

I did my best to follow the instructions in the ZMQ termination whitepaper , but so far I'm failing miserably. 我尽力遵循ZMQ终止白皮书中的说明 ,但到目前为止,我失败了。 I have a parent class, which spawns a listener thread (using win32-pthreads ). 我有一个父类,它产生一个侦听器线程(使用win32-pthreads )。

Accoring to the whitepaper, when terminating, I should set the _stopped flag, delete the context, which in turn would call zmq_term() and release the blocking recv() . 根据白皮书,在终止时,我应该设置_stopped标志,删除上下文,这又将调用zmq_term()并释放阻塞的recv() Instead, what I get is either: 相反,我得到的是:

  • calling delete _zmqContext crashes the application (probably with a segmentation fault) 调用delete _zmqContext会使应用程序崩溃(可能是分段错误)
  • replacing the delete with zmq_term(_zmqContext) does not release the blocking recv() zmq_term(_zmqContext)替换delete不会释放阻塞的recv()

I'm adding a partial code sample, which is long because I'm not sure which part may be important. 我要添加部分代码示例,这很长,因为我不确定哪一部分可能很重要。

AsyncZmqListener.hpp: AsyncZmqListener.hpp:

class AsyncZmqListener
{
public:
    AsyncZmqListener(const std::string uri);
    ~AsyncZmqListener();

    bool Start();
    void Stop();

private:
    static void* _threadEntryFunc(void* _this);     
    void _messageLoop();

private:
    bool _stopped;
    pthread_t _thread;
    zmq::context_t* _zmqContext;
};

AsyncZmqListener.cpp: AsyncZmqListener.cpp:

AsyncZmqListener::AsyncZmqListener(const std::string uri) : _uri(uri)
{
    _zmqContext = new zmq::context_t(1);
    _stopped = false;
}

void AsyncZmqListener::Start()
{
    int status = pthread_create(&_thread, NULL, _threadEntryFunc, this);
}

void AsyncZmqListener::Stop()
{
    _stopped = true;
    delete _zmqContext;             // <-- Crashes the application. Changing to 'zmq_term(_zmqContext)' does not terminate recv()
    pthread_join(_thread, NULL);    // <-- This waits forever
}

void AsyncZmqListener::_messageLoop()
{        
    zmq::socket_t listener(*_zmqContext, ZMQ_PULL);
    listener.bind(_uri.c_str());

    zmq::message_t message;    
    while(!_stopped)
    {
        listener.recv(&message);    // <-- blocks forever
        process(message);
    }
}

PS 聚苯乙烯

I'm aware of this related question , but none of the answers quite match the clean exit flow described in the whitepaper. 我知道这个相关问题 ,但是没有一个答案与白皮书中描述的干净出口流程完全匹配。 I will resolve to polling if I have to... 如果需要,我将决定进行轮询。

ZMQ recv() did unblock after its related context was terminated ZMQ recv()在其相关上下文终止后并未解除阻止

I was not aware that recv() throws an ETERM exception when this happens. 我不知道发生这种情况时recv()会引发ETERM异常。 Revised code that works: 修改后的代码有效:

void AsyncZmqListener::_messageLoop()
{        
    zmq::socket_t listener(*_zmqContext, ZMQ_PULL);
    listener.bind(_uri.c_str());

    zmq::message_t message;    
    while(!_stopped)
    {
        try
        {
            listener.recv(&message);
            process(message);
        }
        catch(const zmq::error_t& ex)
        {
            // recv() throws ETERM when the zmq context is destroyed,
            //  as when AsyncZmqListener::Stop() is called
            if(ex.num() != ETERM)
                throw;
        }
    }
}

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

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