处理消息队列的C#线程

处理消息队列的C#线程,c#,multithreading,message-queue,C#,Multithreading,Message Queue,我有以下要求- 接收消息并将其排队的线程 处理排队消息的线程 现在,第二个线程必须始终处于活动状态-为此,我使用了无限while循环,如下所示: private AutoResetEvent messageReset; private Queue<byte[]> messageQueue; //thread 2 method private void ProcessIncomingMessages() { messageReset.WaitOne(); //wait for si

我有以下要求-

  • 接收消息并将其排队的线程
  • 处理排队消息的线程
  • 现在,第二个线程必须始终处于活动状态-为此,我使用了无限while循环,如下所示:

    private AutoResetEvent messageReset;
    private Queue<byte[]> messageQueue;
    
    //thread 2 method
    private void ProcessIncomingMessages()
    {
     messageReset.WaitOne(); //wait for signal
     while(true)
     {
        if (messageQueue.Count > 0)
        {
            //processing messages
        }
      }
    }
    public void SubmitMessageForProcessing(byte[] message){
                messageQueue.Enqueue(message); //enqueue message
    
                // Release the thread
                messageReset.Set();
    }
    
    private AutoResetEvent messageReset;
    专用队列消息队列;
    //线程2方法
    私有void ProcessIncomingMessages()
    {
    messageReset.WaitOne();//等待信号
    while(true)
    {
    如果(messageQueue.Count>0)
    {
    //处理消息
    }
    }
    }
    用于处理的公用void SubmitMessage(字节[]消息){
    messageQueue.Enqueue(message);//Enqueue message
    //脱线
    messageReset.Set();
    }
    
    现在,这个无限while循环的CPU利用率非常高。 是否有降低CPU利用率的解决方法


    注意:我无法添加任何thread.sleep语句,因为传入消息将以最小延迟显示在UI上。

    在您的示例中,
    while
    循环将一直忙到队列至少有一个元素为止。您可以将信号移动到该循环中,以减少繁忙的等待并使用更少的CPU

    private void ProcessIncomingMessages()
    {
        while(true)
        {
            messageReset.WaitOne(100); //wait for signal
            while (messageQueue.Count > 0)
            {
                //processing messages
            }
        }
    }
    
    另外,除非您有某种自定义的锁定机制,否则如果您希望线程安全,必须使用
    ConcurrentQueue
    而不是
    队列。另外,我在WaitOne调用上设置了一个超时,因为在您检查计数之后,但在到达WaitOne调用之前,设置信号的可能性很小。解决方案中可能存在其他线程问题。如果您对线程问题没有信心,您可能希望使用a,它会为您处理很多细节。

    只需使用a而不是
    队列。它是线程安全的,将在
    Take
    上阻塞,直到有工作人员添加一个项目:

    // Use default constructor to make BlockingCollection FIFO
    private BlockingCollection<byte[]> messageQueue = new BlockingCollection<byte[]>();
    
    //thread 2 method
    private void ProcessIncomingMessages()
    {
        while (true)
        {
            //will block until thread1 Adds a message
            byte[] message = messageQueue.Take();
    
            //processing messages
        }
    }
    public void SubmitMessageForProcessing(byte[] message)
    {
        messageQueue.Add(message); //enqueue message
    }
    
    //使用默认构造函数生成BlockingCollection FIFO
    private BlockingCollection messageQueue=new BlockingCollection();
    //线程2方法
    私有void ProcessIncomingMessages()
    {
    while(true)
    {
    //将一直阻止,直到thread1添加消息
    byte[]message=messageQueue.Take();
    //处理消息
    }
    }
    用于处理的公用void SubmitMessage(字节[]消息)
    {
    messageQueue.Add(message);//将消息排队
    }
    

    EDIT2:我忘了提到,通过使用
    BlockingCollection
    将是FIFO。它实际上将使用
    ConcurrentQueue
    作为项目容器

    如果希望
    BlockingCollection
    的行为类似于后进先出集合,则需要将后进先出的集合传递给构造函数。通常的课程是


    编辑:解释一下您的
    队列如何不是线程安全的,这可能会导致当前代码出现问题

    队列上的Microsoft文档中

    只要不修改集合,队列可以同时支持多个读取器

    这意味着您不能同时读取和写入多个线程

    请看下面的示例,该示例也适用于建议在
    while(true)
    块中移动
    messageReset.WaitOne()

  • SubmitMessageForProcessing
    被调用,并发出信号
    messageReset.Set()
  • 线程2处于活动状态并尝试读取数据
  • 当线程2读取数据
    SubmitMessageForProcessing
    时,调用第二次
  • 现在你同时写和读导致了意想不到的行为(通常是某种异常)

  • 您可能想了解一下,它是线程安全的,并且阻止了
    Take
    谢谢。。你能详细说明一下螺纹的安全性吗。BlockCollection中的线程安全性如何优于Queue中的线程安全性。@HershikaSharma文档中的threadsafety部分可能会比我做更好的解释。但是,如果某些特定的东西不清楚,不要担心问。嗨,弗雷格,阻止收集是否遵循FIFO?下面的场景将如何实现-@HershikaSharma问得好,我实际上忘了提到这一点!是的,
    BlockingCollection
    是在使用默认构造函数时。但是它也可以用作后进先出。@HershikaSharma你是对的,
    BlockingCollection
    使用了
    IProducerConsumerCollection
    界面/模式,设计上不允许偷看。如果您需要该功能,很遗憾您不能使用
    BlockingCollection
    。如果您真的需要这种行为,我将从