2014-09-29 66 views
1

问题:有多个线程访问资源。我需要限制他们的号码为一个常数MaxThreads。无法进入线程池的线程应该会收到错误消息。线程池与BlockingCollection

解决方案:我开始使用下面的算法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()); 
} 
+1

考虑使用[semaphore](http://msdn.microsoft.com/en-us/library/system.threading.semaphore(v = vs.110).aspx)。信号量就像一个酒吧保镖。他允许一定数量的人进出。如果里面的人比酒吧可以处理的人多,他不会允许任何人进入,除非有人离开。您可以使用'WaitOne'重载等待指定时间,然后才会出现超时异常 – oleksii 2014-09-29 12:11:25

回答

5

如果你想保护某些数量的线程可以访问一个关键区域在一次,你将不得不使用SemaphoreSemaphoreSlim。我建议后者,与前者相比,重量轻。

SemaphoreSlim的一个缺点是它们不能跨越过程,但这很好,我们有Semaphore来帮助。

您可以通过超时框架提供的Wait方法来测试Semaphore是否已满。

SemaphoreSlim semaphore = new SemaphoreSlim(3, 3); 

if (!semaphore.Wait(0)) 
{ 
    //Already semaphore full. 
    //Handle it as you like 
} 

http://www.albahari.com/threading/是一个非常好的线程资源。