计数和二进制信号量之间的区别

时间:2012-06-05 13:15:34

标签: operating-system semaphore

Counting和二进制信号量有什么区别。

我在某处看到的是,两者都可以控制已请求资源的N个进程。 两者都采取了自由状态。

二进制信号量和计数信号量可以保护多少资源有限制吗?

一次只允许一个进程使用资源......

还有其他区别吗?上述属性是否正确?

3 个答案:

答案 0 :(得分:31)

实际上,这两种类型都用于同步对共享资源的访问,无论尝试访问的实体是进程还是线程。

区别如下:

二进制信号量是二进制的,它们只能有两个值;一个表示进程/线程在临界区(访问共享资源的代码),其他人应该等待,另一个表示临界区是免费的。

另一方面,计算信号量需要两个以上的值,它们可以具有您想要的任何值。 它们采用的最大值X允许X进程/线程同时访问共享资源。

有关详细信息,请查看此链接 http://www.chibios.org/dokuwiki/doku.php?id=chibios:articles:semaphores_mutexes

修改
计数信号量可以采用的最大值是您希望同时允许进入临界区的进程数。
同样,您可能会遇到需要排除某个资源的情况,但是您知道这个资源可以通过最多个进程(比如X)访问,因此您可以设置一个值为X的计数信号量。

这将允许X进程同时访问该资源;然而,过程X + 1必须等到关键部分中的一个过程结束。

答案 1 :(得分:9)

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

信号量有两部分:一个计数器,以及一个等待访问特定资源的任务列表。信号量执行两个操作:wait(P)[这就像获取锁定],释放(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个任务 - 你希望在3之后执行#1和2。你将如何设计同步?

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&#39的数量大于P的数量会怎样?)

相互排斥使用计数信号量:我希望您为此构建自己的伪代码(让您更好地理解事物!) - 但基本概念是这样的:计数信号量counter = N允许N个任务自由进入临界区。这意味着你有N个任务(或线程,如果你愿意)进入关键部分,但是第N + 1个任务被阻止(继续我们最喜欢的被阻止任务列表),只有当有人V&#39时才通过信号量至少一次。所以信号量计数器,而不是在0和1之间摆动,现在介于0和N之间,允许N个任务自由进入和退出,阻止任何人!

现在,你为什么需要这么奇怪的锁?互不排斥的全部意义是不要让不止一个人访问资源? 认为。 (提示 ...你的计算机中始终只有一个驱动器,对吗......?)

思考:单独计算信号量是否可以实现互斥?如果你有10个资源实例,10个线程进入(通过计数信号量)并尝试使用第一个实例怎么办?

答案 2 :(得分:1)

计数和二进制信号量之间最基本的区别在于:

  1. 二进制信号量无法处理有界等待,因为它只是一个保存二进制值的变量。 计算信号量它可以处理有界等待,因为它已将变量转换为具有队列的结构。
  2. Strcuture实现二进制信号量:  int s;

    计算信号量:  结构S.  {       int s;       队列q;  }

  3. 使用计数信号量现在处理一旦获得CS(关键部分)现在必须等待另一个获得CS,所以不是一个单独的进程。每个过程都有机会获得CS。