什么是信号量?

信号量是一种编程概念,常常用于解决多线程问题。 我对社区的问题: html

什么是信号量,如何使用? 编程


#1楼

所以,想象每一个人都在尝试去洗手间,而洗手间只有必定数量的钥匙。 如今,若是没有足够的键,该人须要等待。 所以,能够将信号量视为表明可用于浴室(系统资源)的那些键集,以供不一样进程(浴室行进者)请求访问。 安全

如今想象一下试图同时去洗手间的两个过程。 那不是一个好状况,而且使用信号量来防止这种状况。 不幸的是,信号量是一种自愿机制,过程(咱们的洗手间)能够忽略它(即,即便有钥匙,仍然有人能够将门打开)。 多线程

二进制/互斥量和计数信号量之间也存在差别。 并发

http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html上查看讲义。 工具


#2楼

构建并发程序有两个基本概念-同步和互斥。 咱们将看到这两种类型的锁(信号灯一般是一种锁定机制)如何帮助咱们实现同步和互斥。 this

信号量是一种编程结构,可经过实现同步和互斥来帮助咱们实现并发。 信号量有两种类型,二进制和计数。 spa

信号量包括两个部分:一个计数器和一个等待访问特定资源的任务列表。 信号量执行两项操做:wait(P)[就像获取锁同样],以及release(V)[相似于释放锁] –这是一个能够对信号量执行的仅有的两项操做。 在二进制信号量中,计数器在逻辑上介于0和1之间。您能够认为它相似于具备两个值的锁:打开/关闭。 计数信号量具备多个计数值。 操作系统

重要的是要理解,信号量计数器跟踪没必要阻塞的任务数量,即它们能够取得进展。 任务被阻止,而且仅在计数器为零时才将其本身添加到信号量列表中。 所以,若是任务没法进行,则将其添加到P()例程的列表中,而后使用V()例程“释放”任务。 线程

如今,很明显地看到如何使用二进制信号量来解决同步和互斥-它们本质上是锁。

例如 同步:

thread A{
semaphore &s; //locks/semaphores are passed by reference! think about why this is so.
A(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
;// some block of code B2
...
}

//thread B{
semaphore &s;
B(semaphore &s): s(s){} //constructor
foo(){
...
...
// some block of code B1
s.V();
..
}

main(){
semaphore s(0); // we start the semaphore at 0 (closed)
A a(s);
B b(s);
}

在上面的示例中,B2仅在B1完成执行后才能执行。 假设线程A首先执行-进入sem.P(),而后等待,由于计数器为0(关闭)。 线程B出现,完成B1,而后释放线程A-而后完成B2。 所以,咱们实现了同步。

如今,让咱们看一下带有二进制信号量的互斥:

thread mutual_ex{
semaphore &s;
mutual_ex(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
//critical section
s.V();
...
...
s.P();
//critical section
s.V();
...

}

main(){
semaphore s(1);
mutual_ex m1(s);
mutual_ex m2(s);
}

互斥也很是简单-m1和m2没法同时进入关键部分。 所以,每一个线程都使用相同的信号量为其两个关键部分提供互斥。 如今,能够有更大的并发性吗? 取决于关键部分。 (想想还有其余方法可使用信号量实现互斥..提示提示:我是否只须要使用一个信号量?)

信号量计数:具备多个值的信号量。 让咱们看看这意味着什么-一个具备多个值的锁? 所以,打开,关闭和……嗯。 互斥或同步中的多级锁有什么用?

让咱们更简单地选择两个:

使用计数信号量进行同步:假设您有3个任务-#1和2在3以后要执行。您将如何设计同步?

thread t1{
...
s.P();
//block of code B1

thread t2{
...
s.P();
//block of code B2

thread t3{
...
//block of code B3
s.V();
s.V();
}

所以,若是您的信号量从关闭开始,请确保将t1和t2阻止添加到了信号量列表中。 而后全部重要的t3出现,完成其业务并释放t1和t2。 他们以什么顺序被释放? 取决于信号量列表的实现。 能够是FIFO,能够基于某些特定的优先级等。 (注意:若是但愿以特定顺序执行t1和t2,而且不知道信号量的实现,请考虑如何布置P和V;)

(发现:若是V的数量大于P的数量会发生什么?)

互斥使用计数信号量:我但愿您为此构建本身的伪代码(使您更好地理解!)-但基本概念是:counter = N的计数信号量使N个任务能够自由进入关键部分。 这意味着您有N个任务(或线程,若是您愿意)进入关键部分,可是第N + 1个任务被阻止(进入咱们最喜欢的阻止任务列表),而且只有当有人V成为信号量时才经过至少一次。 所以,信号量计数器如今再也不在0和1之间摆动,而是在0和N之间摆动,从而容许N个任务自由进出,阻止任何人!

如今,天哪,你为何须要这么愚蠢的东西? 互斥的所有目的不是让一个以上的人访问资源吗? (提示提示...您的计算机并不老是只有一个驱动器,对吗??)

考虑一下 :是否能够经过单独使用计数信号量来实现互斥? 若是您有10个资源实例,而且有10个线程(经过计数信号量)进入并尝试使用第一个实例怎么办?


#3楼

信号量是一种锁定资源的方法,能够确保在执行一段代码时,只有该段代码能够访问该资源。 这样能够防止两个线程同时访问资源,这可能会致使问题。


#4楼

@克雷格:

信号量是一种锁定资源的方法,能够确保在执行一段代码时,只有该段代码能够访问该资源。 这样能够防止两个线程同时访问资源,这可能会致使问题。

这不只限于一个线程。 能够将信号量配置为容许固定数量的线程访问资源。


#5楼

迈克尔·巴尔(Michael Barr) 揭秘互斥量和信号量文章是一个简短的简短介绍,介绍了互斥量和信号量不同凡响的缘由以及什么时候以及不该该使用它们。 我在这里摘录了几个关键段落。

关键是互斥锁应用于保护共享资源,而信号灯应用于信令。 一般,您不该使用信号量来保护共享资源,也不该使用互斥体来发信号。 例如,在使用信号量来保护共享资源方面,保镖类比存在一些问题-您能够经过这种方式使用它们,但可能会致使难以诊断错误。

尽管互斥量和信号量在实现上有一些类似之处,但应始终以不一样的方式使用它们。

最多见(但仍然不正确)的答案是,互斥量和信号量很是类似,惟一的区别是信号量能够大于一个。 几乎全部工程师彷佛都正确地理解了互斥锁是一种二进制标志,用于经过确保在代码的关键部份内相互排斥来保护共享资源。 可是,当被问及如何使用“计数信号量”时,大多数工程师(仅凭信心而定)表达了一些教科书的观点,即它们被用来保护多个等效资源。

...

在这一点上,使用浴室钥匙做为保护共享资源(浴室)的想法作出了一个有趣的类比。 若是商店只有一个浴室,那么一个钥匙就足以保护该资源并防止多我的同时使用它。

若是有多个浴室,则可能会想像一个浴室那样对它们进行键控并作出多个键-这相似于信号灯被滥用。 拥有钥匙后,您实际上并不知道哪一个浴室可用,若是您沿着这条路走,您可能最终将使用互斥锁来提供该信息,并确保您不上已被占用的浴室。

信号量是保护几个基本相同的资源的错误工具,但这是许多人想到并使用它的人。 保镖的类比明显不一样-没有几种相同类型的资源,而是有一种资源能够接受多个同时用户。 我想能够在这种状况下使用信号量,可是在现实世界中不多有此类比喻真正成立的状况-常常有几种相同类型,但仍然有个别资源(例如浴室)没法使用这条路。

...

信号量的正确用法是用于从一个任务向另外一个任务发信号。 互斥锁应始终由使用它保护的共享资源的每一个任务按此顺序获取和释放。 相比之下,使用信号量的任务要么发出信号,要么等待,而不是同时发出信号或等待。 例如,任务1可能包含用于在按下“电源”按钮时张贴(即发出信号或递增信号)特定信号量的代码,而唤醒显示器的任务2则悬停在同一信号量上。 在这种状况下,一个任务是事件信号的产生者; 另外一个消费者。

...

这里要指出的一点是,互斥锁会以一种很差的方式干扰实时操做系统,从而致使优先级倒置,因为资源共享,优先级较低的任务可能会在优先级较高的任务以前执行。 简而言之,当优先级较低的任务使用互斥锁抢​​占资源A,而后尝试抢夺B,但因为B不可用而暂停时,就会发生这种状况。 在等待期间,出现了一个更高优先级的任务,须要A,可是它已经被捆绑,而且因为等待B而没法运行。有不少方法能够解决此问题,可是一般它是固定的经过更改互斥锁和任务管理器。 在这种状况下,互斥锁比二进制信号量要复杂得多,而且在这种状况下使用信号量会致使优先级倒置,由于任务管理器没有意识到优先级倒置而且没法采起措施对其进行纠正。

...

现代互斥量和信号量之间普遍混淆的缘由是历史性的,由于它能够追溯到1974年Djikstra发明的信号量(本文中为大写“ S”)。 在此以前,计算机科学家所知的任何中断安全任务同步和信令机制都没法有效地扩展以用于两个以上的任务。 Dijkstra的革命性,安全且可扩展的信号量已应用于关键部分保护和信号发送。 因而混乱就开始了。

可是,后来出现了基于优先级的抢占式RTOS(例如,VRTX,约1980年),创建RMA的学术论文以及由优先级反转引发的问题以及关于优先级的论文以后,对操做系统开发人员而言这变得显而易见。在1990年的3继承协议中,很明显,互斥锁不只是带有二进制计数器的信号量。

互斥体:资源共享

信号量:信号

在未仔细考虑反作用的状况下,请勿将另外一种药物用于另外一种药物。

相关文章
相关标签/搜索