C# 我的多生产者多消费者方法正确吗?
我不想在System.Collection.Concurrent namespace或PLinq等中使用复杂的构造,所以我决定实现这个经典问题的解决方案。我认为我的想法是尽可能快的(考虑到我的情况是制作速度慢,网络受限)。但我想知道它是否有任何问题(死锁等),所以我想听听你的意见。这是我的密码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
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重新排序等方面不太了解。我知道锁里面总是不需要障碍物。所以我更新了原始代码这个问题非常适合。我投票关闭这个问题,因为它要求代码审查。我不知道代码审查网站。如果它继续存在,也许有人能从中受益。如果它被移除了也没问题