C# 我的多生产者多消费者方法正确吗?

C# 我的多生产者多消费者方法正确吗?,c#,.net,multithreading,synchronization,producer-consumer,C#,.net,Multithreading,Synchronization,Producer Consumer,我不想在System.Collection.Concurrent namespace或PLinq等中使用复杂的构造,所以我决定实现这个经典问题的解决方案。我认为我的想法是尽可能快的(考虑到我的情况是制作速度慢,网络受限)。但我想知道它是否有任何问题(死锁等),所以我想听听你的意见。这是我的密码 using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; nam

我不想在System.Collection.Concurrent namespace或PLinq等中使用复杂的构造,所以我决定实现这个经典问题的解决方案。我认为我的想法是尽可能快的(考虑到我的情况是制作速度慢,网络受限)。但我想知道它是否有任何问题(死锁等),所以我想听听你的意见。这是我的密码

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace SyncTest
{
    static class MultiProducerMultiConsumer
    {
        static Queue<int> queue = new Queue<int>();
        static object syncRootQueue = new object();
        static object syncRootConsumer = new object();
        static ManualResetEvent rseJobReady = new ManualResetEvent(false);
        static bool nextShouldWait = true;

        public static void Start()
        {
            for (int i = 0; i < 2; i++)
            {
                new Thread(Consume).Start(); // queueing into Threadpool is not necessary because Thread wont ever return to pool. 
            }
            for (int i = 0; i < 6; i++)
            {
                new Thread(Produce).Start();
            }
        }


        static void Produce()
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;
            var rnd = new Random(threadId); // ive observed all producers produce same values otherwise.
            int num;
            while (true)
            {
                Thread.Sleep(rnd.Next(600, 900));
                num = rnd.Next();
                Trace.WriteLine(threadId + " producing " + num);
                lock (syncRootQueue)
                {
                    queue.Enqueue(num);
                    if (queue.Count == 1) //which means queue was previously emtpy and there will be always a thread waiting/going to wait for signal.
                        rseJobReady.Set();
                }
            }
        }

        static void Consume()
        {
            int job;
            int threadId = Thread.CurrentThread.ManagedThreadId;
            bool lastItem = false; // only for displaying purpose. can be removed in production code.
            while (true)
            {
                lock (syncRootConsumer) //only one consumer is wanted inside this block
                {
                    if (nextShouldWait) //perf optimization to avoid blocking call to WaitOne
                        rseJobReady.WaitOne();
                    lock (syncRootQueue) //we need always synchronize accessing queue
                    {
                        job = queue.Dequeue();
                        if (nextShouldWait = lastItem = queue.Count == 0)
                        {
                            rseJobReady.Reset(); //wait for signal is required when next consumer enters outer lock
                        }
                    }
                }
                if (lastItem)
                    Trace.WriteLine(threadId + " got last item " + job);
                else
                    Trace.WriteLine(threadId + " consuming " + job);
                Thread.Sleep(new Random().Next(120, 300));
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用系统线程;
命名空间同步测试
{
静态类MultiProducerMultiConsumer
{
静态队列=新队列();
静态对象syncRootQueue=新对象();
静态对象syncRootConsumer=新对象();
静态手动复位事件RSEOBREADY=新手动复位事件(假);
静态bool nextShouldWait=true;
公共静态void Start()
{
对于(int i=0;i<2;i++)
{
新线程(Consume).Start();//不需要排队进入线程池,因为线程永远不会返回到线程池。
}
对于(int i=0;i<6;i++)
{
新线程(product.Start();
}
}
静态空洞生成()
{
int threadId=Thread.CurrentThread.ManagedThreadId;
var rnd=new Random(threadId);//我观察到所有生产者都会产生相同的值。
int-num;
while(true)
{
线程睡眠(rnd.Next(600900));
num=rnd.Next();
Trace.WriteLine(线程ID+“正在生成”+num);
锁定(syncRootQueue)
{
queue.Enqueue(num);
if(queue.Count==1)//这意味着队列以前是emtpy,并且将始终有一个线程等待/准备等待信号。
rseJobReady.Set();
}
}
}
静态void消耗()
{
国际工作;
int threadId=Thread.CurrentThread.ManagedThreadId;
bool lastItem=false;//仅用于显示目的。可在生产代码中删除。
while(true)
{
lock(syncRootConsumer)//此块中只需要一个使用者
{
if(nextShouldWait)//执行优化以避免阻塞对WaitOne的调用
rseJobReady.WaitOne();
lock(syncRootQueue)//我们需要始终同步访问队列
{
job=queue.Dequeue();
如果(nextShouldWait=lastItem=queue.Count=0)
{
rseJobReady.Reset();//当下一个使用者进入外部锁时,需要等待信号
}
}
}
如果(最后一项)
Trace.WriteLine(线程ID+“获取最后一项”+作业);
其他的
Trace.WriteLine(线程ID+“消费”+作业);
Sleep(newrandom().Next(120300));
}
}
}
}

我想对waitone的调用可能可以用一个标志来消除,所以只有在必要时才调用它,但我对内存载体cpu重新排序等方面不太了解。我知道锁内总是没有障碍物。所以我更新了原始代码这个问题非常适合。我投票关闭这个问题,因为它要求代码审查。我不知道代码审查网站。如果它继续存在,也许有人能从中受益。没有问题,如果它被删除了,我想也许对waitone的调用可以用一个标志来消除,所以它只有在必要的时候才会被调用,但我对内存载体cpu重新排序等方面不太了解。我知道锁里面总是不需要障碍物。所以我更新了原始代码这个问题非常适合。我投票关闭这个问题,因为它要求代码审查。我不知道代码审查网站。如果它继续存在,也许有人能从中受益。如果它被移除了也没问题