原文地址: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 ///<summary>
24 /// 线程执行的方法
25 ///</summary>
26 ///<param name="o"></param>
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 }

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

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

第三次运行结果如下:

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

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

线程间同步之 semaphore(信号量)的更多相关文章

  1. Linux系统编程(29)——线程间同步(续篇)

    线程间的同步还有这样一种情况:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行.在pthread库中通过条件变 ...

  2. C++多线程同步之Semaphore(信号量)

    一.线程间同步的几种方式 从上篇博文中可以发现,当多个线程对同一资源进行使用时,会产生“争夺”的情况,为了避免这种情况的产生,也就出现了线程间的同步这个技术.线程间的同步有多种方式,在接下来的博文中我 ...

  3. rtt学习之线程间同步与通信

    一 线程间的同步与互斥:信号量.互斥量.实践集 线程互斥是指对于临界区资源访问的排它性,如多个线程对共享内存资源的访问,生产消费型对产品的操作.临界区操作操作方法有: rt_hw_interrupt_ ...

  4. C#线程间同步无法关闭

    用C#做了个线程间同步的小程序,但每次关闭窗口后进程仍然在,是什么原因? 解决方法: 要加一句 线程.IsBackground = true; 否则退出的只是窗体 上面的方法没看懂... MSDN上说 ...

  5. linux线程间同步方式汇总

    抽空做了下linux所有线程间同步方式的汇总(原生的),包含以下几个: 1, mutex 2, condition variable 3, reader-writer lock 4, spin loc ...

  6. conditon_variable(条件变量)用于线程间同步

    conditon_variable(条件变量)用于线程间同步 condition_variable有5个函数,函数名及对应的功能如下: wait阻塞自己,等待唤醒 wait_for阻塞自己,等待唤醒, ...

  7. c++11 线程间同步---利用std::condition_variable实现

    1.前言 很多时候,我们在写程序的时候,多多少少会遇到下面种需求 一个产品的大致部分流程,由工厂生产,然后放入仓库,最后由销售员提单卖出去这样. 在实际中,仓库的容量的有限的,也就是说,工厂不能一直生 ...

  8. linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁

    Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量.信号量和读写锁. 下面是思维导图:  一.互斥锁(mutex)  锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . ...

  9. Linux进程间通信与线程间同步详解(全面详细)

    引用:http://community.csdn.net/Expert/TopicView3.asp?id=4374496linux下进程间通信的几种主要手段简介: 1. 管道(Pipe)及有名管道( ...

随机推荐

  1. MsSql省市联动表

    drop table area CREATE TABLE [dbo].[Area] ( , ) NOT NULL , ) COLLATE Chinese_PRC_CI_AS NOT NULL , ) ...

  2. Django Errors Archive

    记录使用 Django 开发中遇到的问题,备用 1. 版本要选好,最好安装上 pip,可以省很多麻烦 2. 如果使用 Postgresql,选 8.1 之后的版本,免去 Retruning 之类的错误 ...

  3. (转)JS的parent对象

    ---http://blog.sina.com.cn/s/blog_a15aa5690101a5yz.html top:该变更永远指分割窗口最高层次的浏览器窗口.如果计划从分割窗口的最高层次开始执行命 ...

  4. windows7在局域网中无法映射驱动器问题解决

    昨天下班时闲的蛋疼,因电脑比较慢,因此在计算机的[系统配置中]的启动选项下对[启动项目]和[服务]做了误操作,导致在计算机重启之后声卡.显卡.网卡等许多服务禁用,更令人费解的是内网中断了连接,无法访问 ...

  5. UIScrollView不能响应touch事件的解决办法

    UIScrollView本身事是不支持touch的,我们可以给她添加拓展 #import "UIScrollView+util.h" @implementation UIScrol ...

  6. Hibernate 性能优化之懒加载

    针对数据库中的大数据,不希望特别早的加载到内存中,当用到它的时候才加载 懒加载分为:类的懒加载.集合的懒加载.单端关联的懒加载 类的懒加载    1.在默认情况下,类就是执行懒加载        2. ...

  7. PHP json的插入和解析在数据库中的操作

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. PHP中往数据库中存储json数据在项目开发中也经常遇到,下面我就 ...

  8. _Obj* __STL_VOLATILE* __my_free_list

    今天在读<STL源码剖析>空间配置器第二级时看到了这句,有点不解,于是查阅后知: obj后面是个指针 STL_VOLATILE也应该是个类型定义的吧,程序中应该有define来对它定义.所 ...

  9. Windows Phone 使用 WriteableBitmap后台生成图片

    这几天项目是遇到一个需求,需要后台把几个元素生成到一张图片上,并保存到文件中 private void cutscreen_Click(object sender, EventArgs e) { Gr ...

  10. extjs中rowEditing动态编辑

    我们在使用Grid的rowEditing插件时希望能够根据自己的业务需求能够动态的实现那一列是用户可以编辑的,那一列用户不可编辑,下面给出一个方案能够实现rowEditing的动态编辑功能. 之前我通 ...