如何从c#中的工作线程关闭ZMQ QueueDevice

时间:2014-10-29 19:18:42

标签: c# multithreading zeromq netmq

首次使用ZMQ,我试图设置一个处理许多getimage请求的进程。在我调试时会发生什么异常,我尝试修复并实现一种方法来阻止QueueDevice终止所有线程并优雅地退出。

  1. receiver.Connect(BackendBindAddress);抛出类型为' NetMQ.InvalidException'的未处理异常发生在NetMQ.dll中,错误代码为NetMQ.zmq.ErrorCode.EINVAL。为什么这个异常不会停止进一步执行线程?
  2. 我尝试将QueueDevice设置为静态字段并在关闭消息函数中使用queueDevice.stop(),但随后线程开始抛出TerminatingExceptions和neverexit。那么我可以关闭所有线程和主线程吗?
  3. 测试驾驶代码

        [TestMethod]
        public void ProgramStartupShutdownTest()
        {
            var mockClientWrapper = new Mock<IClient>(MockBehavior.Strict);
    
            var target = new SocketListener(2, mockClientWrapper.Object);
    
            var task = Task.Factory.StartNew(() => target.StartListening("tcp://localhost:81"));
            using (var client = NetMQContext.Create())
            {
               var socket = client.CreateRequestSocket();
               socket.Connect("tcp://localhost:81");
               var m = new NetMQMessage(new ShutdownMessage().CreateMessageFrames());
               socket.SendMessage(m);
            }
    
            var timedout = task.Wait(200);
            Assert.IsTrue(timedout);
        }
    

    代码I正在使用

    private const string BackendBindAddress = "inproc://workers";
    public SocketListener(int numberOfWorkers, IClient client )
        {
            numberOfThreads = numberOfWorkers;
            _client = client;
        }
    
    public void StartListening(string address)
        {
            StartZeroMQ(address, context =>
            {
                for (var i = 0; i <= numberOfThreads; i++)
                {
                    var t = new Thread(WorkerRoutine);
                    t.Start(
                            new WorkerParamters
                            {
                                Context = context,
                                Client = _client
                            }
                        );
                }
            });
        }
    
    
        private void StartZeroMQ(string address, Action<NetMQContext> setupWorkers)
        {
            using (var context = NetMQContext.Create())
            {
                var queueDevice = new QueueDevice(context, address, BackendBindAddress, DeviceMode.Blocking);
                setupWorkers(context);
                queueDevice.Start();
            }
        }
    
        struct WorkerParamters
        {
            public NetMQContext Context;
            public IClient Client;
        }
    
        private static void WorkerRoutine(object startparameter)
        {
                var wp = (WorkerParamters) startparameter;
                var client = wp.Client;
                using (var receiver = wp.Context.CreateResponseSocket())
                {
                    receiver.Connect(BackendBindAddress);
                    var running = true;
                    while (running)
                    {
                            var message = receiver.ReceiveMessage();
                            var letter = Message.ParseMessageFrame(message,
                                                                   imageMessage => GetImage(imageMessage, client),
                                                                   videoMessage => GetVideo(videoMessage, client),
                                                                   shutdownMessage =>
                                                                   {
                                                                       running = false;
                                                                       return true;
                                                                   });
    
                            receiver.Send(letter.ToJson(), Encoding.Unicode);
                    }
                }
        }
    

1 个答案:

答案 0 :(得分:1)

为了克服这个问题,我在设备中添加了Initialize方法,在启动worker之前调用它,并在调用worker启动设备之后调用它。

您可以从here获取代码(您需要从存储库中编译项目),稍后我会添加一个拉取请求。

你也可以手工编写设备逻辑,它不应该复杂。