How can I clean up properly when recv is blocking?

眉间皱痕 提交于 2019-12-06 05:11:59

问题


Consider the example code below (I typed it up quickly as an example, if there are errors it doesn't matter - I'm interested in the theory).

bool shutDown = false; //global

int main()
{
  CreateThread(NULL, 0, &MessengerLoop, NULL, 0, NULL);
  //do other programmy stuff...
}


DWORD WINAPI MessengerLoop( LPVOID lpParam )
{
  zmq::context_t context(1);
  zmq::socket_t socket (context, ZMQ_SUB);
  socket.connect("tcp://localhost:5556");
  socket.setsockopt(ZMQ_SUBSCRIBE, "10001 ", 6);

  while(!shutDown)
  {
    zmq_msg_t getMessage;
    zmq_msg_init(&getMessage);
    zmq_msg_recv (&getMessage, socket, 0); //This line will wait forever for a message
    processMessage(getMessage); 
  }
}

A thread is created to wait for incoming messages and to handle them appropriately. The thread is looping until shutDown is set to true.

In ZeroMQ the Guide specifically states what must be cleaned up, namely the messages, socket and context.

My issue is: Since recv will wait forever for a message, blocking the thread, how can I shut down this thread safely if a message is never received?


回答1:


The blocking call will exit in a few ways. First, and this depends on your language and binding, an interrupt (Ctrl-C, SIGINT, SIGTERM) will exit the call. You'll get back (again, depending on your binding) an error or a null message (libzmq returns an EINTR error).

Second, if you terminate the context in another thread, the blocking call will also exit (libzmq returns an ETERM error).

Thirdly, you can set timeouts on the socket so it will return in any case after some timeout, if there's no data. We don't often do this but it can be useful in some cases.

Finally, what we do in practice is never do blocking receives but use zmq_poll to find out when sockets have messages waiting, then receive from those sockets. This is how you scale out to handling more sockets.




回答2:


You can use non-blocking call flag ZMQ_DONTWAIT

  while(!shutDown)
  {
    zmq_msg_t getMessage;
    zmq_msg_init(&getMessage);
    while(-1 == zmq_msg_recv(&getMessage, socket, ZMQ_DONTWAIT))
    {
      if (EAGAIN != errno || shutDown)
      {
        break;
      }
      Sleep(100);
    }
    processMessage(getMessage); 
  }



回答3:


Whenever zmq context is destroyed, zmq_msg_recv will receive a -1. I use this as the terminating condition in all of my code.

while (!shutdown)
{
    ..
    ..
    int rc = zmq_msg_recv (&getMessage, socket, 0);
    if (rc != -1)
    {
      processMessage;
    }
    else 
      break;
}

Remember to destroy the zmq context at the end of your main() for a proper clean-up.

zmq_ctx_destroy(zctx); 



回答4:


Lets say you have a class say SUB (subscriber) that manages the receive of your ZMQ messages. In the destructor or exit function of your main function/class, call the following:

pub->close();

///
/// Close the publish context
///
void PUB::close()
{
    zmq_close (socket);
    zmq_ctx_destroy (context);
}

This will enable that 'recv' blocking terminates with error message that you can ignore. The application will exit comfortably in the right way. This is the right method. Good luck!



来源:https://stackoverflow.com/questions/16212526/how-can-i-clean-up-properly-when-recv-is-blocking

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!