这个例子试图用 C# 3.5 下支持的 Thread 与 Semaphore 来说明,如何让多线程异步(async)处理事情。
比较适合于 A,B 两人抢麦发言的场合。
1 using System; 2 using System.Threading; 3 4 namespace testSemaphore 5 { 6 class Program 7 { 8 Semaphore se = new Semaphore(1, 1); 9 static void Main(string[] args) 10 { 11 12 Program p = new Program(); 13 14 p.test(); 15 16 Console.WriteLine("main end, mainthreadid = {0}", System.Threading.Thread.CurrentThread.ManagedThreadId); 17 } 18 19 void test() 20 { 21 object param1 = new object[] { "Thread A", 1000 }; 22 object param2 = new object[] { "Thread B", 20 }; 23 24 Thread t1 = new Thread(new ParameterizedThreadStart(ThreadProc)); 25 Thread t2 = new Thread(new ParameterizedThreadStart(ThreadProc)); 26 27 t1.Start(param1); 28 t2.Start(param2); 29 } 30 31 //void ThreadProc(string name, int startdelay) 32 void ThreadProc(object args) 33 { 34 string name = (string)((object[])args)[0]; 35 int startdelay = (int)((object[])args)[1]; 36 37 Console.WriteLine("{0}: COME IN, threadid = {1}", name, System.Threading.Thread.CurrentThread.ManagedThreadId); 38 39 System.Threading.Thread.Sleep(startdelay); 40 41 Console.WriteLine("{0}: START, threadid = {1}", name, System.Threading.Thread.CurrentThread.ManagedThreadId); 42 43 for (int i = 0; i < 10; ++i) 44 { 45 se.WaitOne(); 46 47 Random r = new Random(); 48 49 int s = r.Next(50,1000); 50 51 Console.WriteLine("{0}: i = {1}, sleep({2}), threadid = {3}", name, i, s, System.Threading.Thread.CurrentThread.ManagedThreadId); 52 53 System.Threading.Thread.Sleep(s); 54 55 se.Release(); 56 } 57 58 Console.WriteLine("{0}: END, threadid = {1}", name, System.Threading.Thread.CurrentThread.ManagedThreadId); 59 } 60 } 61 } 62 63 64 //main end, mainthreadid = 1 65 //Thread A: COME IN, threadid = 3 66 //Thread B: COME IN, threadid = 4 67 //Thread B: START, threadid = 4 68 //Thread B: i = 0, sleep(168), threadid = 4 69 //Thread B: i = 1, sleep(827), threadid = 4 70 //Thread A: START, threadid = 3 71 //Thread A: i = 0, sleep(913), threadid = 3 72 //Thread B: i = 2, sleep(109), threadid = 4 73 //Thread A: i = 1, sleep(552), threadid = 3 74 //Thread B: i = 3, sleep(175), threadid = 4 75 //Thread A: i = 2, sleep(380), threadid = 3 76 //Thread B: i = 4, sleep(139), threadid = 4 77 //Thread A: i = 3, sleep(768), threadid = 3 78 //Thread B: i = 5, sleep(781), threadid = 4 79 //Thread A: i = 4, sleep(341), threadid = 3 80 //Thread B: i = 6, sleep(523), threadid = 4 81 //Thread A: i = 5, sleep(457), threadid = 3 82 //Thread B: i = 7, sleep(927), threadid = 4 83 //Thread A: i = 6, sleep(961), threadid = 3 84 //Thread B: i = 8, sleep(229), threadid = 4 85 //Thread A: i = 7, sleep(464), threadid = 3 86 //Thread B: i = 9, sleep(481), threadid = 4 87 //Thread B: END, threadid = 4 88 //Thread A: i = 8, sleep(342), threadid = 3 89 //Thread A: i = 9, sleep(865), threadid = 3 90 //Thread A: END, threadid = 3 91 //请按任意键继续. . .
一开始的 Semaphore(1, 1) 代表初始值是1,最大值是1,也就是两人抢一个麦。想像一下,当这个麦被A或B某一个抢到时,se内部的值会等于0,也就是说,没抢到的那位要等到 se 变为1(别人还麦后)。
Semaphore se = new Semaphore(1, 1);
另一个地方就是 给被调用线程传初始参数,这可以通过申明满足 void func( object arg ) 的线程处理函数来满足 delegate ParameterizedThreadStart 需要的形式。
通过 Semaphore 可以满足某种在 同步 结构下的 异步等待形式。。比如,A通过消息队列机制让B做事,但A在发送完 “B请开始做事” 后,A要等待B的做事结果,这时,A就应该被阻塞在那里等待。这样就可以通过 new Semaphore(0,1) 来让A 一运行到 se.WaitOne() 时就停在那里的状态,而B在收到做事通知后开始做事,等事情做完后,调用 se.Relase(),就可以让 A脱离等待状态了。