[zeromq-dev] Clean exit in clrzmq. C# "using" vs close (disposal of ZmqContext hangs)

Matthew Darnall dnallicus at gmail.com
Tue Feb 18 00:35:24 CET 2014

Hi Robert,

When you call term on a context in libzmq, it will block until all
messages from the sockets are sent (unless you change the LINGER
default) and the sockets are explicitly closed.

In the clrzmq binding, the dispose method on a context calls zmq_term
on the context.  The dispose method on a socket calls zmq_close on the
socket.  Unlike many other bindings (like the java one), the clrzmq
version of a context does NOT remember all the sockets it created and
call zmq_close on them.

Note that the finalizer for the context and socket in clrzmq do NOT
call the close methods, so the garbage collector won't do it for you.
I don't think we want the GC to clean it, because the sockets are
created in other threads and sockets aren't thread safe.  This is
probably also the reason ZmqContext in clrzmq doesn't close the
sockets for you.  I am actually surprised the java binding does do
this, as I would think it would cause thread issues.

To summarize, FIX1 works because the zmq_term is never called.  Fix 2
and 3 work because the socket that would normally block the zmq_term
is now closed.


(copy of email from Robert.Hauser at flextronics.com

I noticed weird behavior running the zguide C# lpClient.cs example
with no server running. After finishing retries it would hang (during
disposing ZmqContext) instead of exit. A reduced case that behaves the
same is below.

        public static void Main(string[] args)
            using (ZmqContext context = ZmqContext.Create())   //FIX1
ZmqContext context = ZmqContext.Create();
                var client = context.CreateSocket(SocketType.REQ);
//FIX2 using (var client = context.CreateSocket(SocketType.REQ)) { }

                //FIX3 client.Close();
                Console.WriteLine("end using");

Any one of replacing lines at FIX1, FIX2, or inserting FIX3 behave
better. FIX1 still results in a blocking infinite timeout down in
libzmq but it moved it off the main thread to the GC thread which was
enough to let the program exit, it seems.

If the original lpClient.cs is not correct, what is the right approach
... to explicitly call Close() on a C# ZmqSocket? Or is the GC for an
abandoned ZmqSocket supposed to handle it? Or maybe ZmqContext
disposal shouldn't be hanging in this case; this seems doubtful but
stack is below (for the code above with no FIX).  -Robert

 	libzmq_d.dll!zmq::signaler_t::wait(int timeout_)  Line 174 + 0x48 bytes	C++
 	libzmq_d.dll!zmq::mailbox_t::recv(zmq::command_t * cmd_, int
timeout_)  Line 74 + 0x15 bytes	C++
 	libzmq_d.dll!zmq::ctx_t::terminate()  Line 112 + 0x21 bytes	C++
 	libzmq_d.dll!zmq_ctx_destroy(void * ctx_)  Line 173 + 0xa bytes	C++
 	[External Code]	
 	clrzmq.dll!ZeroMQ.Interop.ContextProxy.Terminate() Line 35 + 0x37 bytes	C#
 	clrzmq.dll!ZeroMQ.Interop.ContextProxy.Dispose(bool disposing) Line
73 + 0xa bytes	C#
 	clrzmq.dll!ZeroMQ.Interop.ContextProxy.Dispose() Line 65 + 0x16 bytes	C#
 	clrzmq.dll!ZeroMQ.ZmqContext.Dispose(bool disposing) Line 186 + 0x22 bytes	C#
 	clrzmq.dll!ZeroMQ.ZmqContext.Dispose() Line 172 + 0x16 bytes	C#
 	lpClient.exe!lpClient.lpClient.Main(string[] args) Line 31 + 0x4e bytes	C#

Legal Disclaimer:
The information contained in this message may be privileged and
confidential. It is intended to be read only by the individual or
entity to whom it is addressed or by their designee. If the reader of
this message is not the intended recipient, you are on notice that any
distribution of this message, in any form, is strictly prohibited. If
you have received this message in error, please immediately notify the
sender and delete or destroy any copy of this message!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.zeromq.org/pipermail/zeromq-dev/attachments/20140217/2019b277/attachment.htm>

More information about the zeromq-dev mailing list