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

C# 如何在c中从工作线程关闭ZMQ QueueDevice#,c#,multithreading,zeromq,netmq,C#,Multithreading,Zeromq,Netmq,第一次使用ZMQ,我正在尝试设置一个进程来处理许多getimage请求。当我调试时会发生一些异常,我试图修复这些异常,并实现一种停止QueueDevice的方法,终止所有线程并优雅地退出 receiver.Connect(后端绑定地址);在NetMQ.dll中发生类型为“NetMQ.InvalidException”的未处理异常,错误代码为NetMQ.zmq.ErrorCode.EINVAL。为什么这个异常不停止线程的进一步执行 我已尝试将QueueDevice设置为静态字段,并在shutdow

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

  • receiver.Connect(后端绑定地址);在NetMQ.dll中发生类型为“NetMQ.InvalidException”的未处理异常,错误代码为NetMQ.zmq.ErrorCode.EINVAL。为什么这个异常不停止线程的进一步执行
  • 我已尝试将QueueDevice设置为静态字段,并在shutdown message函数中使用QueueDevice.stop(),但随后线程开始抛出TerminationExceptions和neverexit。那么我可以关闭所有线程和主线程吗
  • 测试驱动代码

        [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);
        }
    
    [TestMethod]
    公共无效程序StartupShutdownTest()
    {
    var mockClientWrapper=newmock(MockBehavior.Strict);
    var target=newsocketlistener(2,mockClientWrapper.Object);
    var task=task.Factory.StartNew(()=>target.StartListening(“tcp://localhost:81"));
    使用(var client=NetMQContext.Create())
    {
    var socket=client.CreateRequestSocket();
    插座。连接(“tcp://localhost:81");
    var m=new NetMQMessage(new ShutdownMessage().CreateMessageFrames());
    socket.SendMessage(m);
    }
    var timedout=task.Wait(200);
    Assert.IsTrue(timedout);
    }
    
    我正在使用的代码

    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);
                    }
                }
        }
    
    private const string backendbinddress=”inproc://workers";
    公共SocketListener(int numberOfWorkers,IClient客户端)
    {
    numberOfThreads=numberOfWorkers;
    _客户=客户;
    }
    公共侦听(字符串地址)
    {
    StartZeroMQ(地址,上下文=>
    {
    对于(var i=0;i GetImage)(imageMessage,客户端),
    videoMessage=>GetVideo(videoMessage,客户端),
    关机消息=>
    {
    运行=错误;
    返回true;
    });
    Send(letter.ToJson(),Encoding.Unicode);
    }
    }
    }
    
    为了克服这个问题,我在设备中添加了一个初始化方法,在启动工人之前调用它,在调用工人之后启动设备

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


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

    我得到了一半的答案,inproc协议要求在你连接到它之前绑定套接字。谢谢,我正在考虑编写它,但在几个月后,当我的zmq知识变得更粗糙时,我不得不继续维护它。也就是说,我不想学习如何使用它在我所学的基础上使用民意测验。