Search code examples
c#disposezeromq

ZeroMQ context destruction causes poller to ETERM but doesn't continue


I have a very simple thread loop

public void ClientLoop(object AContext)
{
    var context = (ZMQ.Context) AContext;

    Socket client = CreateServerSocket(context);

    while (true)
    {
        try
        {
            Context.Poller(requestTimeout*1000, client);
        }
        catch (Exception e)
        {
            if (e.Errno == ETERM)
            {
                //Catch a termination error. 
                Debug.WriteLine("Terminated! 1");
                return;
            }
        }
    }
}

And a dispose that looks like the following

public void Dispose()
{
    _context.Dispose();
}

The client socket is created with linger set to zero and a poller in handler set. The socket is also a request socket.

Once the dispose is called the poller excepts and falls into the try except block. However after the dispose doesn't continue like I thought it would. This is how the ZGuide says to handle destruction of the context and sockets however it doesn't seem to be working in this case.

What have I missed?


Solution

  • However after the dispose doesn't continue like I thought it would.

    You mean the call to Dispose hangs/blocks? That is because you did not close the client socket before you return from the thread. (My syntax below may be wrong but you get the idea)

            if (e.Errno == ETERM)
            {
                //Catch a termination error. 
                Debug.WriteLine("Terminated! 1");
                client.Close();
                return;
            }
    

    Setting linger to 0 is not enough - that just prevents the socket closure from blocking. You must still close the socket in your worker thread to prevent the _context.Dispose() from blocking.

    This is how the ZGuide says to handle destruction of the context and sockets...

    Well - that's true but there is an important qualifier in the document:

    We'll get to multithreading in the next chapter, but because some of you will, despite warnings, will try to run before you can safely walk, below is the quick and dirty guide to making a clean exit in a multithreaded ØMQ application.

    Later in the document they describe how to do a clean shutdown by having a dedicated socket in each thread which listens to a kill signal. Consider enhancing your worker thread by doing something similar. This way you can request each thread to shut itself down by sending each thread a message - each thread then exits its run loop, does a clean close on it's socket(s) and exits. Once all threads have exited you can safely dispose of the context without having any errors.