Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有资源的生产者-消费者_C#_Multithreading_Producer Consumer - Fatal编程技术网

C# 具有资源的生产者-消费者

C# 具有资源的生产者-消费者,c#,multithreading,producer-consumer,C#,Multithreading,Producer Consumer,我试图用一组资源实现生产者/消费者模式,因此每个线程都有一个与其关联的资源。例如,我可能有一个任务队列,其中每个任务都需要一个StreamWriter来写入其结果。每个任务还必须向其传递参数 我从Joseph Albahari的实现开始(我的修改版本见下文) 我将Action队列替换为Action队列,其中T是资源,并将与线程关联的资源传递给Action。但是,这就给我留下了如何将参数传递给操作的问题。显然,操作必须替换为委托,但这留下了任务排队时如何传递参数的问题(从ProducerConsu

我试图用一组资源实现生产者/消费者模式,因此每个线程都有一个与其关联的资源。例如,我可能有一个任务队列,其中每个任务都需要一个
StreamWriter
来写入其结果。每个任务还必须向其传递参数

我从Joseph Albahari的实现开始(我的修改版本见下文)

我将
Action
队列替换为
Action
队列,其中
T
是资源,并将与线程关联的资源传递给
Action
。但是,这就给我留下了如何将参数传递给
操作
的问题。显然,
操作
必须替换为委托,但这留下了任务排队时如何传递参数的问题(从
ProducerConsumerQueue
类外部)。有什么办法吗

class ProducerConsumerQueue<T>
    {
        readonly object _locker = new object();            
        Thread[] _workers;
        Queue<Action<T>> _itemQ = new Queue<Action<T>>();

        public ProducerConsumerQueue(T[] resources)
        {
            _workers = new Thread[resources.Length];

            // Create and start a separate thread for each worker
            for (int i = 0; i < resources.Length; i++)
            {
                Thread thread = new Thread(() => Consume(resources[i]));
                thread.SetApartmentState(ApartmentState.STA);
                _workers[i] = thread;
                _workers[i].Start();
            }
        }        

        public void Shutdown(bool waitForWorkers)
        {
            // Enqueue one null item per worker to make each exit.
            foreach (Thread worker in _workers)
                EnqueueItem(null);

            // Wait for workers to finish
            if (waitForWorkers)
                foreach (Thread worker in _workers)
                    worker.Join();
        }

        public void EnqueueItem(Action<T> item)
        {
            lock (_locker)
            {
                _itemQ.Enqueue(item);           // We must pulse because we're
                Monitor.Pulse(_locker);         // changing a blocking condition.
            }
        }

        void Consume(T parameter)
        {
            while (true)                        // Keep consuming until
            {                                   // told otherwise.
                Action<T> item;
                lock (_locker)
                {
                    while (_itemQ.Count == 0) Monitor.Wait(_locker);
                    item = _itemQ.Dequeue();
                }
                if (item == null) return;         // This signals our exit.
                item(parameter);                           // Execute item.
            }
        }
    }
类ProducerConsumerQueue
{
只读对象_locker=新对象();
线程【】u工人;
队列_itemQ=新队列();
公共ProducerConsumerQueue(T[]资源)
{
_workers=新线程[resources.Length];
//为每个工作线程创建并启动一个单独的线程
for(int i=0;i消耗(资源[i]);
SetApartmentState(ApartmentState.STA);
_工人[i]=线程;
_workers[i].Start();
}
}        
公共无效关闭(bool waitForWorkers)
{
//为每个工作人员排队一个空项以进行每个退出。
foreach(线程工作线程)
排队项目(空);
//等待工人完成
if(等待工人)
foreach(线程工作线程)
worker.Join();
}
公共无效排队项(操作项)
{
锁(储物柜)
{
_itemQ.Enqueue(item);//我们必须脉冲,因为我们
Monitor.Pulse(_locker);//更改阻塞条件。
}
}
无效消耗(T参数)
{
while(true)//继续消费直到
{//我不是这么说的。
行动项目;
锁(储物柜)
{
while(_itemQ.Count==0)Monitor.Wait(_locker);
item=_itemQ.Dequeue();
}
if(item==null)return;//这表示我们退出。
项(参数);//执行项。
}
}
}

ProducerConsumerQueue
中的类型
T
不一定是您的资源,它可以是包含您的资源的复合类型。使用.NET4最简单的方法是使用
Tuple
。product/consumer队列只吃并吐出
T
,因此在
操作中,您可以使用属性获取资源和参数。如果您使用的是
Tuple
,您将使用
Item1
获取资源,使用
Item2
获取参数

如果不使用.NET4,则过程类似,但您只需创建自己的类:

public class WorkItem<T>
{
    private StreamWriter resource;
    private T parameter;

    public WorkItem(StreamWriter resource, T parameter)
    {
        this.resource = resource;
        this.parameter = parameter;
    }

    public StreamWriter Resource { get { return resource; } }
    public T Parameter { get { return parameter; } }
}
现在我们可以使用这样的类:

var processor = new Processor();
for (int i = 0; i < 10; i++)
    processor.Process(i);
var处理器=新处理器();
对于(int i=0;i<10;i++)
处理程序(i);

同时计划的任务不会超过三个,每个任务都有自己的
StreamWriter
资源可回收。

问题是我不想为每个任务提供自己的StreamWriter。我希望每个StreamWriter都属于一个线程,该线程在执行任务时将重用它。
var processor = new Processor();
for (int i = 0; i < 10; i++)
    processor.Process(i);