博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程间同步之 semaphore(信号量)
阅读量:6041 次
发布时间:2019-06-20

本文共 4111 字,大约阅读时间需要 13 分钟。

原文地址:http://www.cnblogs.com/yuqilin/archive/2011/10/16/2214429.html

semaphore 可用于进程间同步也可用于同一个进程间的线程同步。

semaphore 非常类似于mutex ,

共同点:semaphore和mutex都是内核对象,都可用于进程间的同步,并且都特别占用系统资源(线程的同步包括用户模式下的同步和内核模式下的同步,如果用内核对象来同步被保护的资源,系统需要从用户模式切换到内核模式,这个时间大概是1000个cpu周期)。

区别为:mutex只能由一个线程(进行)访问被保护的资源。semaphore 是一种带计数的mutex的锁定,可定义同时访问被保护的资源的线程数。

信号量有一个使用计数器,这个使用计数器,是信号量的最大资源计数和当前资源计数的差值。

信号量的规则如下:

a、如果当前资源计数大于0,那么信号量处于触发状态。

b、如果当前资源计数等于0,那么信号量处于未触发状态。

c、系统绝对不会让当前资源计数变为负数。

d、当前资源计数绝对不会大于最大最大资源计数

如:6个进程需要同时使用打印机,而电脑上只有四台打印机,则打印机是被保护的资源,信号量为4。则需要用semaphore来同步。

1、线程间的sempahore同步

使用下面的例子来讲解(见注释部分):

1        static void Main(string[] args)  2         {
3 int threadCount = 6; 4 int sempaphoreCount = 4; 5 // maximumCount-initialCount 之间的差值为已经锁定的 semaphore的数量 此实例中已经指定占用了0个信号量 6 //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步 7 System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(sempaphoreCount, sempaphoreCount, "sempaphore"); 8 9 Thread[] threads = new Thread[threadCount]; 10 for (int i = 0; i < threadCount; i++) 11 {
12 threads[i] = new Thread(ThreadMain); 13 threads[i].Start(sempaphore); 14 } 15 for (int i = 0; i < threadCount; i++) 16 {
17 threads[i].Join(); 18 } 19 Console.WriteLine("All threads finished!"); 20 Console.ReadKey(); 21 } 22 23 /// 24 /// 线程执行的方法 25 /// 26 /// 27 static void ThreadMain(object o) 28 {
29 Semaphore semaphore = o as Semaphore; 30 Trace.Assert(semaphore != null, "o must be a semphore type"); 31 32 bool isCompleted = false; 33 while (!isCompleted) 34 {
35 //锁定信号量,如果锁定计数已经达到最高计数限制,则等待600毫秒。如果在600毫秒后未能获得锁定,则返回false。 36 if (semaphore.WaitOne(600, false)) 37 {
38 try 39 {
40 Console.WriteLine("Thread {0} locks the semaphore ", Thread.CurrentThread.ManagedThreadId); 41 Thread.Sleep(2000); 42 } 43 finally 44 {
45 //解除资源的锁定。参数为退出信号量的次数。占用一个信号量故退出一个。 46 semaphore.Release(1); 47 Console.WriteLine("Thread {0} release the semaphore", Thread.CurrentThread.ManagedThreadId); 48 isCompleted = true; 49 } 50 } 51 else 52 {
53 Console.WriteLine("Timeot for thread {0}; wait again", Thread.CurrentThread.ManagedThreadId); 54 } 55 } 56 }

注意:如果出现 WaitOne 就一个要有对应的Release 即获取信号量后,一定要释放。

运行结果如下:

可以看到,四个线程(11、12、13、14)获得了锁定。线程15,16需要等待。该等待会重复进行,直到获得锁定的线程之一解除了信号量的锁定。

2、进程间的sempahore同步

下面的例子将使用信号量来同步进程,一个应用程序可以有二个实例运行(如果只允许有一个实例来运行,最优之选是mutex,其次才是信号量)。虽然这个例子不太实用,但完全可以说明semaphore的特性。

大家先看代码:

1         static void Main(string[] args)  2         {
3 //定义可同步运行的可用实例数 4 int CreateNew = 2; 5 6 //定义可同步运行的最大实例数 7 int MaxCreateNew = 5; 8 9 // maximumCount-initialCount 之间的差值为已经锁定的 semaphore的数量 此实例中已经指定占用了3个信号量 计算方式为(MaxCreateNew-CreateNew) 10 //Semaphore的第三个参数为信号量的名称,如果设定了名称,则可用于进程间的同步,如果没有设置名称则只能用于进程内的线程同步 11 System.Threading.Semaphore sempaphore = new System.Threading.Semaphore(CreateNew, MaxCreateNew, "sempaphoreProcess"); 12 13 if (sempaphore.WaitOne(100, false)) 14 {
15 Console.WriteLine("系统正在运行……"); 16 Console.ReadKey(); 17 } 18 else 19 {
20 MessageBox.Show("当前已经有 " + CreateNew + " 个实例在运行,系统将退出!", "您好", MessageBoxButtons.OK, MessageBoxIcon.Information); 21 } 22 23 }

生成解决方案后运行三次程序:

第一次运行和第二次运行结果如下:

第三次运行结果如下:

 现在已经完成只允许有两个应用程序实例在同时运行。

注意:信号量的进程同步和信号量的应用程序的名称无关。只要使用了同样名称的信号量,他们之前就存在了一种协约。

你可能感兴趣的文章
时间轴
查看>>
java 获取系统当前时间的方法
查看>>
Ubuntu 10.04升级git 到1.7.2或更高的可行方法
查看>>
Spring Security4实战与原理分析视频课程( 扩展+自定义)
查看>>
第一周博客作业
查看>>
thinkpython2
查看>>
oracle recyclebin与flashback drop
查看>>
svmlight使用说明
查看>>
Swing 和AWT之间的关系
查看>>
Mysql设置自增长主键的初始值
查看>>
Android计时器正确应用方式解析
查看>>
获取post传输参数
查看>>
ASP生成静态页面的方法
查看>>
HDU 1325 Is It A Tree? 判断是否为一棵树
查看>>
Shell命令-文件压缩解压缩之gzip、zip
查看>>
个人总结
查看>>
uva 673 Parentheses Balance
查看>>
Bzoj 2252: [2010Beijing wc]矩阵距离 广搜
查看>>
css 禁止选中文本
查看>>
bzoj2165
查看>>