在我的应用程序中,我使用不同的线程(每个活动传输一个线程)。例如,我想限制活动的转移,将其他即将到来的转移放在队列中。
现在我的解决方案是检查是否有空间进行另一个活动传输,如果没有,我会将请求放入队列列表中。每次我完成一个活动时,我都会从队列中挑选一个。(但我想我的解决方案真的很脏)
有没有一种安排活动线程的好方法?
使用信号量是一个不错(且整洁)的选择吗?
在我的应用程序中,我使用不同的线程(每个活动传输一个线程)。例如,我想限制活动的转移,将其他即将到来的转移放在队列中。
现在我的解决方案是检查是否有空间进行另一个活动传输,如果没有,我会将请求放入队列列表中。每次我完成一个活动时,我都会从队列中挑选一个。(但我想我的解决方案真的很脏)
有没有一种安排活动线程的好方法?
使用信号量是一个不错(且整洁)的选择吗?
您可以使用 BlockingCollection 来管理队列,例如:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
public class Program
{
private readonly BlockingCollection<int> _queue = new BlockingCollection<int>();
private void run()
{
const int CONSUMER_COUNT = 8;
Task[] tasks = new Task[CONSUMER_COUNT];
for (int i = 0; i < CONSUMER_COUNT; ++i)
{
int id = i;
tasks[i] = Task.Run(() => process(id));
}
Console.WriteLine("Press <return> to start adding to the queue.");
Console.ReadLine();
for (int i = 0; i < 100; ++i)
{
Console.WriteLine("Adding item #{0}", i);
_queue.Add(i);
}
Console.WriteLine("Press <return> to close the queue.");
Console.ReadLine();
_queue.CompleteAdding();
Console.WriteLine("Waiting for all tasks to exit.");
Task.WaitAll(tasks);
Console.WriteLine("Finished waiting for all tasks. Press <return> to exit.");
Console.ReadLine();
}
private void process(int id)
{
Console.WriteLine("Process {0} is starting.", id);
foreach (var item in _queue.GetConsumingEnumerable())
{
Console.WriteLine("Process {0} is processing item# {1}", id, item);
Thread.Sleep(200); // Simulate long processing time.
}
Console.WriteLine("Process {0} is stopping.", id);
}
private static void Main()
{
new Program().run();
}
}
}
请注意,这里的关键是GetConsumingEnumerable()
返回一个可枚举,如果队列中没有项目,它将阻塞,但如果没有项目并且生产者调用了,它将退出CompleteAdding()
。这使得在工作线程退出时很容易控制。