5天不再惧怕多线程——第四天 信号量

转载 2012年03月21日 14:18:16
 今天整理“信号量”的相关知识,其实想想也蛮有趣的,锁,互斥,信号量都可以实现线程同步,在framework里面主要有三种。

<1>:ManualResetEvent

<2>:AutoResetEvent

<3>: Semaphore

 

好,下面就具体看看这些玩意的使用。

 

一:ManualResetEvent

      该对象有两种信号量状态True和False,好奇的我们肯定想知道True和False有什么区别,稍后的例子见分晓,有三个方法值得学习一下。

1:WaitOne

     该方法用于阻塞线程,默认是无限期的阻塞,有时我们并不想这样,而是采取超时阻塞的方法,如果超时就放弃阻塞,这样也就避免了无限期

       等待的尴尬。

2:Set

     手动修改信号量为True,也就是恢复线程执行。

3:ReSet

     手动修改信号量为False,暂停线程执行。

 

好了,下面举个例子说明一下。

 

<1>  信号量初始为False,WaitOne采用无限期阻塞,可以发现线程间可以进行交互。

 1 public class Example
 
2 {
 3     public static void Main()
 4     {
 5         Thread t = new Thread(Run);
 6 
 
 7         t.Name = "Jack";
 8 
 9         Console.WriteLine("当前时间:{0}  {1} {1},我是主线程,收到请回答。", DateTime.Now, t.Name);
10 
11         t.Start();
12 
13         Thread.Sleep(5000);
14 
15         mr.Set();
16 
17         Console.Read();
18     }
19 
20     static ManualResetEvent mr = new ManualResetEvent(false);
21 
22     static void Run()
23     {
24         mr.WaitOne();
25 
26         Console.WriteLine("\n当前时间:{0}  主线程,主线程,{1}已收到!", DateTime.Now, Thread.CurrentThread.Name);
27     }
28 

 

 

<2> 信号量初始为True,WaitOne采用无限期阻塞,实验发现WaitOne其实并没有被阻塞。

 static ManualResetEvent mr = new ManualResetEvent(true);

 

<3>信号量初始为False,WaitOne采用超时2s,虽然主线程要等5s才能进行Set操作,但是WaitOne已经等不及提前执行了。

 1 public class Example
 2 {
 3     public static void Main()
 4     {
 5         Thread t = new Thread(Run);
 6 
 7         t.Name = "Jack";
 8 
 9         Console.WriteLine("当前时间:{0}  {1} {1},我是主线程,收到请回答。", DateTime.Now, t.Name);
10 
11         t.Start();
12 
13         Thread.Sleep(5000);
14 
15         mr.Set();
 
16 
17         Console.Read();
18     }
19 
20     static ManualResetEvent mr = new ManualResetEvent(false);
21 
22     static void Run()
23     {
24         mr.WaitOne(2000);
25 
26         Console.WriteLine("\n当前时间:{0}  主线程,主线程,{1}已收到!", DateTime.Now, Thread.CurrentThread.Name);
27     }
28 }

 


二:AutoResetEvent

      在VS对象浏览器中,我们发现AutoResetEvent和ManualResetEvent都是继承于EventWaitHandle,所以基本功能是一样的,不过值得注意

的一个区别是WaitOne会改变信号量的值,比如说初始信号量为True,如果WaitOne超时信号量将自动变为False,而ManualResetEvent则不会。

 1 public class Example
 
2 {
 3     public static void Main()
 4     {
 5         Thread t = new Thread(Run);
 6 
 7         t.Name = "Jack";
 
 8 
 9         t.Start();
10 
11         Console.Read();
12     }
13 
 
14     static AutoResetEvent ar = new AutoResetEvent(true);
15 
16     static void Run()
17     {
18         var state = ar.WaitOne(1000, true);
 
19 
20         Console.WriteLine("我当前的信号量状态:{0}", state);
21 
22         state = ar.WaitOne(1000, true);
23 
24         Console.WriteLine("我恨你,不理我,您现在的状态是:{0}", state);
25 
26     }
27 }
 

 

 

三:Semaphore 

     这玩意是.net 4.0新增的,用于控制线程的访问数量,默认的构造函数为initialCount和maximumCount,表示默认设置的信号量个数和

最大信号量个数,其实说到底,里面是采用计数器来来分配信号量,当你WaitOne的时候,信号量自减,当Release的时候,信号量自增,然而

当信号量为0的时候,后续的线程就不能拿到WaitOne了,所以必须等待先前的线程通过Release来释放。

 

好了,下面还是举例子来说明一下:

 

<1> initialCount=1,maximunCount=10,WaitOne采用无限期等待。

 1 namespace ConsoleApplication3
 
2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 
 6         {
 7 
 8             Thread t1 = new Thread(Run1);
 9             t1.Start();
10 
11             Thread t2 = new Thread(Run2);
12             t2.Start();
13 
14             Console.Read();
15         }
16 
17         static Semaphore sem = new Semaphore(1, 10);
18 
19         static void Run1()
20         {
21             sem.WaitOne();
22 
23             Console.WriteLine("大家好,我是Run1");
24         }
25 
26         static void Run2()
27         {
28             sem.WaitOne();
29 
30             Console.WriteLine("大家好,我是Run2");
31         }
32     }
33 }
 

我们悲剧的发现t2线程不能执行,我们知道WaitOne相当于自减信号量,然而默认的信号量个数为1,所以t2想执行必须等待t1通过Release来释放。

1         static void Run1()
2         {
3             sem.WaitOne();
4 
5             Console.WriteLine("大家好,我是Run1");
6 
7             sem.Release();
8         }
 
 

可能有的同学要问,我不是设置了maximunCount=10吗?为什么没有起到作用?是的,默认情况下是没有起到作用,必须要我们手动干预一下,

我们知道调用Release方法相当于自增一个信号量,然而Release有一个重载,可以指定自增到maximunCount个信号量,这里我就在主线程上

Release(10),看看效果。

 1 namespace ConsoleApplication3
 2 {
 3     class Program
 4     {
 
 5         static void Main(string[] args)
 6         {
 7 
 8             Thread t1 = new Thread(Run1);
 9             t1.Start();
10 
11             Thread t2 = new Thread(Run2);
12             t2.Start();
13 
14             Thread.Sleep(1000);
15 
16             sem.Release(10);
17 
18             Console.Read();
19         }
20 
21         static Semaphore sem = new Semaphore(1, 10); 
 
23         static void Run1()
24         {
25             sem.WaitOne();
26 
27             Console.WriteLine("大家好,我是Run1");
28         }
29 
30         static void Run2()
31         {
32             sem.WaitOne();
33 
34             Console.WriteLine("大家好,我是Run2");
35         }
36     }
37 }
 


<2> Semaphore命名,升级进程交互。

      在VS对象浏览器中发现Semaphore是继承字WaitHandle,而WaitHandle封装了win32的一些同步机制,所以当我们给Semaphore命名的时候

就会在系统中可见,下面举个例子,把下面的代码copy一份,运行两个程序。

 1 namespace ConsoleApplication3
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 
 7 
 8             Thread t1 = new Thread(Run1);
 9             t1.Start();
10 
11             Thread t2 = new Thread(Run2);
12             t2.Start();
13 
14             Console.Read();
15         }
16 
17         static Semaphore sem = new Semaphore(3, 10, "cnblogs");
18 
19         static void Run1()
20         {
21             sem.WaitOne();
22 
23             Console.WriteLine("当前时间:{0} 大家好,我是Run1", DateTime.Now);
24         }
25 
26         static void Run2()
27         {
28             sem.WaitOne();
29 
30             Console.WriteLine("当前时间:{0} 大家好,我是Run2", DateTime.Now);
31         }
32     }
33 }

 

 

 

是的,我设置了信号量是3个,所以只能有三个线程持有WaitOne,后续的线程只能苦苦的等待。

5天不再惧怕多线程——第四天 信号量

作者:一线码农 转自:
  • whw8007
  • whw8007
  • 2014年10月28日 11:22
  • 523

5天不再惧怕多线程

5天不再惧怕多线程——第一天 尝试Thread 5天不再惧怕多线程——第二天 锁机制 5天不再惧怕多线程——第三天 互斥体 5天不再惧怕多线程——第四天 信号量 5天不再惧怕多线程——第五天 ...
  • jefftian2008
  • jefftian2008
  • 2012年05月02日 07:54
  • 194

5天不再惧怕多线程——第二天 锁机制

作者:一线码农 转自:http://www.cnblogs.com/huangxincheng/archive/2012/03/14/2397068.html
  • whw8007
  • whw8007
  • 2014年10月28日 11:13
  • 710

5天不再惧怕多线程——第三天 互斥体

作者:一线码农 转自:http://www.cnblogs.com/huangxincheng/archive/2012/03/16/2402320.html
  • whw8007
  • whw8007
  • 2014年10月28日 11:22
  • 654

5天不再惧怕多线程——第五天 线程池

作者:一线码农 转自:http://www.cnblogs.com/huangxincheng/archive/2012/03/18/2405039.html
  • whw8007
  • whw8007
  • 2014年10月28日 11:24
  • 652

5天不再惧怕多线程——第一天 尝试Thread

转自http://www.cnblogs.com/huangxincheng/archive/2012/03/14/2395279.html 原本准备在mongodb之后写一个lucene....
  • kaka20080622
  • kaka20080622
  • 2014年03月25日 11:42
  • 284

python爬虫(多线程&锁&信号量)

1、多线程(无锁):threading.Thread(target = ***).start() 2、多线程(锁 & 单线程): threading.Lock() threading.Thread(...
  • trb331617
  • trb331617
  • 2017年06月04日 09:09
  • 689

Linux多线程——使用信号量同步线程

信号量、同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对象不同而已。但是下面介绍的信号量的接口是用于线程的信号量,注意不要跟用于进程间通信的信号量混淆。相似地,线程同步...
  • ljianhui
  • ljianhui
  • 2013年09月01日 00:09
  • 44486

C++多线程实例-信号量

windows下的信号量: 使用信号量内核对象进行线程同步主要会用到 CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()、 WaitForS...
  • Blues1021
  • Blues1021
  • 2015年03月23日 00:01
  • 1758

windows多线程同步机制---信号量

1 信号量     通知的作用,和事件类似.但是与事件不同.事件只维护一个值0或者1.     信号量维护一个变量,0时无信号,大于0有信号.        2 信号量的使用     2.1...
  • rankun1
  • rankun1
  • 2016年02月17日 20:26
  • 474
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:5天不再惧怕多线程——第四天 信号量
举报原因:
原因补充:

(最多只允许输入30个字)