即使在上下文終止后,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. I have a parent class, which spawns a listener thread (using win32-pthreads).

我盡力遵循ZMQ終止白皮書中的說明,但到目前為止,我失敗了。我有一個父類,它產生一個監聽器線程(使用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(). Instead, what I get is either:

根據白皮書,當終止時,我應該設置_stopped標志,刪除上下文,然后調用zmq_term()並釋放阻塞recv()。相反,我得到的是:

  • 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);
    }
}

P.S.

附:

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...

我知道這個相關問題,但沒有一個答案與白皮書中描述的干凈退出流程完全匹配。如果我必須......我會決定投票

1 个解决方案

#1


3  

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. Revised code that works:

當發生這種情況時,我不知道recv()會拋出一個ETERM異常。修改后的代碼有效:

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

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2013/09/15/725f676a2ba081a987e5ba65df6df82d.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com