Remove Thread.interrupt() restriction.
See original GitHub issueThe wiki says:
“Context.term() must be called before interrupting a thread by Thread.interrupt. Otherwise internal pipe which is used to signal ZMQ commands will be shutdown unexpectedly.”
However, in some cases this means that there is no clean way for an application to shut down when it is blocked on recv().
Consider a thread (thread B) that is blocked on a socket’s recv().
Suppose the main thread (thread A) of the application wants to shut down, it needs to cleanly terminate thread B. This typically involves sending an interrupt to thread B to unblock, but wait! we need to call Context.term() first. However, the wiki says:
“Close all the sockets properly otherwise Context.term() will wait forever”
OK, we need to close the socket first, but wait! The ZMQ guide says:
“Isolate data privately within its thread and never share data in multiple threads. The only exception to this are ØMQ contexts, which are threadsafe.”
Hmm, so the only safe way to close the socket is on the thread that is currently blocked (thread B), too bad we can’t do that.
So now the only way for thread B to unblock is to wait for a new message or a timeout (which may have been set to no timeout). If there are no more messages and there is no timeout, the thread will be blocked indefinitely. But regardless, there should be a means to preemptively unblock the thread.
Even if we were to ignore the shutdown problem, this restriction also leads to more awkward code because now the context needs to be exposed to other threads where it might not have been necessary without the restriction.
In fact, if you look at the Java example in the ZMQ guide and even the examples in this repository, it breaks the interrupt rule.
This is a pretty common pattern you see throughout the code:
while (!Thread.currentThread ().isInterrupted ()) {
...
}
receiver.close ();
context.term ();
Notice how it expects an interrupt before closing the socket and context.
Issue Analytics
- State:
- Created 10 years ago
- Comments:16 (9 by maintainers)
Today I stumbled upon this, which is very informative about
Thread.interrupt()
,Thread.interrupted
, andInterruptedException
in Java.I looked through the codebase and found 2 places where we appear to be swallowing an InterruptedException – I made a PR to fix that: #423.
I don’t think that my PR solves this issue, but hopefully it is a step in the right direction.
At this point, I’m thinking the problem is that we aren’t checking
Thread.interrupted()
often enough in our code, and there must be at least one place where we should be detecting that the thread is interrupted and taking the opportunity to shut down cleanly, but we aren’t.Thank you for the comment.
“Close all the sockets properly otherwise Context.term() will wait forever” not actually means socket.close must be called before Context.term is called. Because Context.term() waits until all the ZMQ sockets are closed, a thread which creates the sockets has responsibility to close its sockets.
The pattern in the guide is also misleading. It was my boring translation of C examples.
must have been correct guide. Sorry for the confusing.
Other example might be useful for clean exit is https://github.com/zeromq/jeromq/blob/master/src/test/java/guide/interrupt.java
When the term is called, all the blocking call(usually recv) will raise an Exception, then you can do any cleanup including closing zmq socket.