0
votes

I'm creating project using ZeroMQ. I need functions to start and to kill thread. Start function seems to work fine but there are problems with stop function.

private Thread _workerThread;
private object _locker = new object();
private bool _stop = false;

public void Start()
    {
        _workerThread = new Thread(RunZeroMqServer);
        _workerThread.Start();
    }

    public void Stop()
    {
        lock (_locker)
        {
            _stop = true;
        }

        _workerThread.Join();
        Console.WriteLine(_workerThread.ThreadState);
    }

    private void RunZeroMqServer()
    {
        using (var context = ZmqContext.Create())
        using (ZmqSocket server = context.CreateSocket(SocketType.REP))
        {
            /*
            var bindingAddress = new StringBuilder("tcp://");
            bindingAddress.Append(_ipAddress);
            bindingAddress.Append(":");
            bindingAddress.Append(_port);
            server.Bind(bindingAddress.ToString());
            */

            //server.Bind("tcp://192.168.0.102:50000");
            server.Bind("tcp://*:12345");

            while (!_stop)
            {
                string message = server.Receive(Encoding.Unicode);
                if (message == null) continue;

                var response = ProcessMessage(message);
                server.Send(response, Encoding.Unicode);

                Thread.Sleep(100);
            }
        }
    }

Maybe someone have any idea about this Stop() function, why it doesn't kill thread? I got hint that I should use Thread.MemoryBarrier and volatile but have no idea how it should works. There is also ProcessMessage() function to process messages, I just didn't copy it to don't litter :)

1

1 Answers

1
votes

The problem seems to be that you're calling a blocking version of ZmqSocket.Receive. While it's waiting to receive a message it's not processing the rest of your code, so it never hits the loop condition.

The solution is to use one of the non-blocking methods, or one that has a timeout. Try this:

string message = server.Receive(Encoding.Unicode, TimeSpan.FromMilliseconds(100));

This should return after 100ms if no message is received, or earlier if a message arrives. Either way it will get a shot at the loop condition.


As to the _stop flag itself...

When you're accessing variables from multiple threads locking is a good idea. In the case of a simple flag however, both reading and writing are pretty much atomic operations. In this case it's sufficient to declare it as volatile (private volatile bool _stop = false;) to tell the compiler to make sure it always actually reads the current value each time you tell it to.