我尽力按照ZMQ termination whitepaper中的说明进行操作,但到目前为止,我失败了。 我有一个父类,它产生一个监听器线程(使用win32-pthreads)。
根据白皮书的说法,在终止时,我应该设置_stopped
标记,删除上下文,然后调用zmq_term()
并释放阻止recv()
。相反,我得到的是:
delete _zmqContext
会导致应用程序崩溃(可能存在分段错误)zmq_term(_zmqContext)
替换删除操作不会释放阻止recv()
我正在添加部分代码示例,这很长,因为我不确定哪个部分可能很重要。
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::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。
我知道这个related question,但没有一个答案与白皮书中描述的干净退出流程完全匹配。如果必须,我会决定进行民意调查......
答案 0 :(得分:4)
ZMQ recv()
在相关上下文终止后取消阻止
当发生这种情况时,我不知道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;
}
}
}