zeromqnetmq

Create NetMQ Socket on one thread and operate on another?


I understand that NetMQ sockets are not thread safe. I'm trying to understand the exact boundaries of this. Must all access to a socket (creation, connect/bind and send/receive) be on the same thread? Or is it safe to create on one thread then pass that socket to another thread for send/receive operations? This is what appears to happen with the use of poller. What about connect, is it safe to create on one thread, connect and then pass the socket to another thread for send/receive? I guess I could just go read the code, but I'm interested in the intent of the developers. From my experiments it appears that the library does not enforce single threading with any runtime checks.


Solution

  • As Felix said, "as long as there is no concurrency" it's fine to use the socket at any point its lifecycle in different threads.

    To extend Felix's comment (which is the answer), remember that the connect function doesn't directly connect anything. It only tells the socket's management thread to start the process of connecting. When the connect function returns, the socket is likely not actually connected to the remote peer yet.

    The part of Felix's comment "and connect is complete" (apologies, Felix, if I've got the wrong interpretation of your comment!) I think refers to an assumption that the thread that gets passed the socket is simply going to get going and write or read from the socket (as appropriate to the socket type). This may not be appropriate in the application if it matters that the socket is actually in a connected state when it tries writing to it. However, the standard properties of the different socket types concerning what they do with messages when the socket is not in a connected state normally satisfies most application's needs (e.g. a PUB socket drops sent messages if there is no connected peer). If not, one can use socket monitor to discover the actual connection state.

    Regardless, one must observe the "no concurrency" rule. For example, if the start-up thread is calling the connect function, a second thread that uses the socket absolutely must not do anything with it until it knows that the start up thread has returned from the call to connect. That syncronisation can of course be achieved in numerous ways.

    I'm quite interested to try ZMQ in Rust. Because that language has such a strong concept of ownership, it's probably a lot more proof against making concurrency mistakes. So if the program passes a socket from one thread to another, I think that means that the first thread can no longer (compiler error messages at build) do anything to that socket.