问题:有多个线程访问资源。我需要将它们的数量限制为常数MaxThreads
。无法进入线程池的线程应该收到错误消息。
解决方案:我开始在下面的算法中使用BlockingCollection<string> pool
,但我发现BlockingCollection
需要调用CompleteAdding
,我无法做到,因为我总是获取传入的线程(我在下面的示例中硬编码为10用于调试目的),考虑Web请求。
public class MyTest {
private const int MaxThreads = 3;
private BlockingCollection<string> pool;
public MyTest() {
pool = new BlockingCollection<string>(MaxThreads);
}
public void Go() {
var addSuccess = this.pool.TryAdd(string.Format("thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
if (!addSuccess) Console.WriteLine(string.Format("thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine(string.Format("Adding thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine(string.Format("Pool size: {0}", pool.Count));
// simulate work
Thread.Sleep(1000);
Console.WriteLine("Thread ID#{0} " + Thread.CurrentThread.ManagedThreadId + " is done doing work.");
string val;
var takeSuccess = this.pool.TryTake(out val);
if (!takeSuccess) Console.WriteLine(string.Format("Failed to take out thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
Console.WriteLine("Taking out " + val);
Console.WriteLine(string.Format("Pool size: {0}", pool.Count));
Console.WriteLine(Environment.NewLine);
}
}
static void Main()
{
var t = new MyTest();
Parallel.For(0, 10, x => t.Go());
}
关于如何更好地实现这一目标的任何想法?
谢谢!
P.S。多线程新手在这里,如果您对阅读材料有任何建议,我将非常感谢他们。
LE:根据我得到的答案,我能够使用此算法实现所需的行为:
public class MyTest {
private const int MaxThreads = 3;
private SemaphoreSlim semaphore;
public MyTest() {
semaphore = new SemaphoreSlim(MaxThreads, MaxThreads);
}
public void Go() {
Console.WriteLine(string.Format("In comes thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
semaphore.Wait();
try {
Console.WriteLine(string.Format("Serving thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
// simulate work
Thread.Sleep(1000);
Console.WriteLine(string.Format("Out goes thread ID#{0}", Thread.CurrentThread.ManagedThreadId));
}
finally {
semaphore.Release();
}
}
}
static void Main()
{
var t = new MyTest();
Parallel.For(0, 10, x=> t.Go());
}
答案 0 :(得分:5)
如果您想保护一次可以访问关键区域的特定数量的线程,则必须使用Semaphore或SemaphoreSlim。我建议使用后者,与前者相比,重量轻。
SemaphoreSlim
的一个缺点是它们不会在交叉过程中起作用,但我们可以Semaphore
帮忙。
您可以通过超时框架提供的Wait方法测试信号量是否已满。
SemaphoreSlim semaphore = new SemaphoreSlim(3, 3);
if (!semaphore.Wait(0))
{
//Already semaphore full.
//Handle it as you like
}
http://www.albahari.com/threading/是一个非常好的线程资源。