Search code examples
c#zeromqdisposenetmq

How to dispose a Poller with a blocked socket?


I have single socket, which is blocked on sending the frame and I would like to dispose poller ( and everything related to it ). However, I cannot do it -- calling dispose on socket throws an exception, and calling dispose on poller completely blocks.

Please note, I am using SendFrame and I could use TrySendFrame, but the purpose of this example is to actually block the socket and find a way how to clean up everything.

Example:

private Program()
{
    const string address = "tcp://localhost:5000";

    var socket = new DealerSocket();
    socket.Options.SendHighWatermark = 1;
    socket.Options.Identity = Encoding.ASCII.GetBytes(Guid.NewGuid().ToString("N"));
    socket.Connect(address);

    var poller = new NetMQPoller();
    poller.Add(socket);
    socket.SendReady += OnSendReady;
    poller.RunAsync();

    Thread.Sleep(5000);
    Console.WriteLine("Disposing");
    poller.Dispose(); // get stuck on this one
    Console.WriteLine("Disposed");
}

private void OnSendReady(object sender, NetMQSocketEventArgs e)
{
    Console.WriteLine("0");
    e.Socket.SendFrame("hello");
    Console.WriteLine("1");
    e.Socket.SendFrame("hello"); // this will block
    Console.WriteLine("2");
}

Tested with NetMQ 3.3.3.4 (my primary version for now) and 4.0.0.1.


Solution

  • 1) Always zeroize ZMQ_LINGER. Always. Right upon a socket instantiation, so as to prevent otherwise inadvertent blocking on graceful termination { .close() | .term() } operations ( be it a controlled or un-controlled activation of termination ops ( as you already have faced it ) ).

    2) Avoid blocking designs. Principally. Each blocking state creates a state, in which all your code is out-of-control. Got it?