基元线程同步构造之信号量(Semaphore)

  信号量(semaphore)不过是由内核维护的 int32变量而已,(说通俗点就是好比一个线程容器里面允许执行的线程数,0计数就是允许执行的0个线程数,1就是允许执行的1个线程数,2就是允许执行的2个线程数,等等一次类推。。。。。。,0就是当前执行的线程数占满了容器没空余的了)

    当信号量为0时,在信号量上等待的线程会全部阻塞;

    当信号量大于0时,就解除阻塞。

  在一个信号量上等待的一个线程解除阻塞时,内核自动从信号量的计数中减1,线程运行完后调用Release,计数就加1。信号量还关联了一个最大的Int32值,当前计数绝不允许超过最大计数。下面展示了semaphore类的样子: 


 public sealed class Semaphore :WaitHandle{
    //初始化信号量:初始请求数为initialCount,最大请求数为maximumCount
    public Semaphore(Int32 initialCount,Int32 maximumCount);
    public Int32 Release();//调用Release(1);返回上一个计数
    public Int32 Release(Int32 releaseCount);//返回上一个计数     
 }
initialCount:就是初始化信号量时,解除阻塞的线程数。

maximumCount:就是信号量允许执行的最大线程数。
 

  一个自动重置事件在行为上和最大计数为1的信号量非常相似。两者的区别在于,可以在一个自动重置事件上连续多次调用Set,同时仍然只有一个线程解除阻塞。相反,在一个信号量上连续多次调用Release,会使它的内部计数一直递增,这可能解除大量线程的阻塞。如果在一个信号量上多次调用Release,会导致它的计数超过最大计数,这是Release会抛出一个SemaphoreFullException.

  请看MSDN中的一个例子:

  

 1 using System;
 2 using System.Threading;
 3 
 4 public class Example
 5 {
 6     // A semaphore that simulates a limited resource pool.
 7     //
 8     private static Semaphore _pool;
 9 
10     // A padding interval to make the output more orderly.
11     private static int _padding;
12 
13     public static void Main()
14     {
15         // Create a semaphore that can satisfy up to three
16         // concurrent requests. Use an initial count of zero,
17         // so that the entire semaphore count is initially
18         // owned by the main program thread.
19         //初始化时允许解除的阻塞线程数量为0,最大的执行线程数为3,所以在第执行完第44行代码之前,开启的子线程中的代码都不会执行,如果注释掉第45行代码,这5个子线程都不会执行,如果改成:new Semaphore(1,3)初始化时允许解除的阻塞线程数量为1,最大执行的线程数为3,所以在执行完31行代码后会有一个子线程在运行的,如果注释掉第45行代码,就会只有一个信号量慢慢的运行完这5个子线程
20         _pool = new Semaphore(0, 3);
21 
22         // Create and start five numbered threads. 
23         //
24         for (int i = 1; i <= 5; i++)
25         {
26             Thread t = new Thread(new ParameterizedThreadStart(Worker));
27 
28             // Start the thread, passing the number.
29             //
30             t.Start(i);
31         }
32 
33         // Wait for half a second, to allow all the
34         // threads to start and to block on the semaphore.
35         //
36         Thread.Sleep(500);
37 
38         // The main thread starts out holding the entire
39         // semaphore count. Calling Release(3) brings the 
40         // semaphore count back to its maximum value, and
41         // allows the waiting threads to enter the semaphore,
42         // up to three at a time.
43         //
44         Console.WriteLine("Main thread calls Release(3).");
45         _pool.Release(3);//此句代码的通俗意思就是重新再增加3个可以执行的线程,如果初始化new semaphore(1,5)运行完这代代码就是1+3=4个线程数解除阻塞了,如果初始化为new  semaphore(0,5)运行完这段代码就是0+3=3个线程数解除阻塞了。
46         //Console.WriteLine("_pool {0}", _pool.Release());
47         //Console.WriteLine("_pool {0}", _pool.Release());
48         //Console.WriteLine("_pool {0}", _pool.Release());
49         //Console.WriteLine("_pool {0}", _pool.Release());
50         //Console.WriteLine("_pool {0}", _pool.Release());
51 
52         Console.WriteLine("Main thread exits.");
53 
54        // Thread.Sleep(5000);
55        // Console.WriteLine("_pool {0}", _pool.Release());
56 
57         Console.ReadLine();
58     }
59 
60     private static void Worker(object num)
61     {
62         // Each worker thread begins by requesting the
63         // semaphore.
64         Console.WriteLine("Thread {0} begins " +
65             "and waits for the semaphore.", num);
66         _pool.WaitOne();
67 
68         // A padding interval to make the output more orderly.
69         int padding = Interlocked.Add(ref _padding, 100);
70 
71         Console.WriteLine("Thread {0} enters the semaphore.", num);
72 
73         // The thread's "work" consists of sleeping for 
74         // about a second. Each thread "works" a little 
75         // longer, just to make the output more orderly.
76         //模拟阻塞线程
77          Thread.Sleep(1000 + padding);
78 
79         Console.WriteLine("Thread {0} releases the semaphore.", num);
80         Console.WriteLine("Thread {0} previous semaphore count: {1}",
81             num, _pool.Release());
82     }
83 }
运行的其中之一的一个结果为:
Thread 2 begins and waits for the semaphore.
Thread 3 begins and waits for the semaphore.
Thread 4 begins and waits for the semaphore.
Thread 1 begins and waits for the semaphore.
Thread 5 begins and waits for the semaphore.
Main thread calls Release(3).
Thread 5 enters the semaphore.
Thread 5 releases the semaphore.
Thread 5 previous semaphore count: 0
Thread 1 enters the semaphore.
Thread 1 releases the semaphore.
Thread 1 previous semaphore count: 0
Thread 3 enters the semaphore.
Thread 3 releases the semaphore.
Thread 3 previous semaphore count: 0
Main thread exits.
Thread 2 enters the semaphore.
Thread 2 releases the semaphore.
Thread 2 previous semaphore count: 1 //执行这段代码前。信号量(semaphore)中还有两个线程在执行(当前运行运行的线程和下面还没运行完的一个线程,所以剩余1个线程的信号量(semaphore)可以执行.
Thread 4 enters the semaphore.
Thread 4 releases the semaphore.
Thread 4 previous semaphore count: 2 //执行这段代码前。信号量(semaphore)中有2个空闲的位置,可以执行线程了。

 这只是自己的理解,不正确的望各位大侠们指教。。。。。。。。。。。。。。。

原文地址:https://www.cnblogs.com/huaan011/p/3578652.html