互斥型信号量必须是同一个任务申请,同一个任务释放,其他任务释放无效。同一个任务可以递归申请。
二进制信号量,一个任务申请成功后,可以由另一个任务释放。
二进制信号量实现任务互斥:
打印机资源只有一个, abc 三个任务共享,当 a 取得使用权后,为了防止其他任务错误地释放了信号量 () ,必须将打印机房的门关起来 ( 进入临界段 ) ,用完后,释放信号量,再把门打开 ( 出临界段 ) ,其他任务再进去打印。 ( 而互斥型信号量由于必须由取得信号量的那个任务释放,故不会出现其他任务错误地释放了信号量的情况出现,故不需要有临界段。互斥型信号量是二进制信号量的子集。 )
二进制信号量实现任务同步:
a 任务一直等待信号量, b 任务定时释放信号量,完成同步功能
互斥量表现互斥现象的数据结构,也被当作二元信号灯。一个互斥基本上是一个多任务敏感的二元信号,它能用作同步多任务的行为,它常用作保护从中断来的临界段代码并且在共享同步使用的资源。
Mutex
本质上说就是一把锁,提供对资源的独占访问,所以
Mutex
主要的作用是用于互斥。
Mutex
对象的值,只有
0
和
1
两个值。这两个值也分别代表了
Mutex
的两种状态。值为
0,
表示锁定状态,当前对象被锁定,用户进程
/
线程如果试图
Lock
临界资源,则进入排队等待;值为
1
,表示空闲状态,当前对象为空闲,用户进程
/
线程可以
Lock
临界资源,之后
Mutex
值减
1
变为
0
。
Mutex
可以被抽象为四个操作:
-
创建
Create
-
加锁
Lock
-
解锁
Unlock
-
销毁
Destroy
Mutex
被创建时可以有初始值,表示
Mutex
被创建后,是锁定状态还是空闲状态。在同一个线程中,为了防止死锁,系统不允许连续两次对
Mutex
加锁
(
系统一般会在第二次调用立刻返回
)
。也就是说,加锁和解锁这两个对应的操作,需要在同一个线程中完成。
不同操作系统中提供的
Mutex
函数
:
动作
/
系统
Win32
Linyx
Solaris
创建
CreateMutex
pthread_mutex_init
mutex_init
加锁
WaitForSingleObject
pthread_mutex_lock
mutex_lock
解锁
ReleaseMutex
pthread_mutex_unlock
mutex_unlock
销毁
CloseHandle
pthread_mutex_destroy
mutex_destroy
信号量
(Semaphore)
,有时被称为信号灯,是在多线程环境下使用的一种设施
,
它负责协调各个线程
,
以保证它们能够正确、合理的使用公共资源。
信号量可以分为几类:
只允许信号量取
0
或
1
值,其同时只能被一个线程获取。
信号量取值是整数,它可以被多个线程同时获得,直到信号量的值变为
0
。
每个信号量
s
除一个整数值
value
(计数)外,还有一个等待队列
List
,其中是阻塞在该信号量的各个线程的标识。当信号量被释放一个,值被加一后,系统自动从等待队列中唤醒一个等待中的线程,让其获得信号量,同时信号量再减一。
信号量通过一个计数器控制对共享资源的访问,信号量的值是一个非负整数,所有通过它的线程都会将该整数减一。如果计数器大于
0
,则访问被允许,计数器减
1
;如果为
0
,则访问被禁止,所有试图通过它的线程都将处于等待状态。
计数器计算的结果是允许访问共享资源的通行证。因此,为了访问共享资源,线程必须从信号量得到通行证,
如果该信号量的计数大于
0
,则此线程获得一个通行证,这将导致信号量的计数递减,否则,此线程将阻塞直到获得一个通行证为止。当此线程不再需要访问共享资源时,它释放该通行证,这导致信号量的计数递增,如果另一个线程等待通行证,则那个线程将在那时获得通行证。
Semaphore
可以被抽象为五个操作:
-
创建
Create
-
等待
Wait
:
线程等待信号量,如果值大于
0
,则获得,值减一;如果只等于
0
,则一直线程进入睡眠状态,知道信号量值大于
0
或者超时。
-
释放
Post
执行释放信号量,则值加一;如果此时有正在等待的线程,则唤醒该线程。
-
试图等待
TryWait
如果调用
TryWait
,线程并不真正的去获得信号量,还是检查信号量是否能够被获得,如果信号量值大于
0
,则
TryWait
返回成功;否则返回失败。
-
销毁
Destroy
信
号量,是可以用来保护两个或多个关键代码段,这些关键代码段不能并发调用。在进入一个关键代码段之前,线程必须获取一个信号量。如果关键代码段中没有任何
线程,那么线程会立即进入该框图中的那个部分。一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程
释放信号量。为了完成这个过程,需要创建一个信号量,然后将
Acquire Semaphore VI
以及
Release Semaphore VI
分别放置在每个关键代码段的首末端。确认这些信号量
VI
引用的是初始创建的信号量。
动作
/
系统
Win32
POSIX
创建
CreateSemaphore
sem_init
等待
WaitForSingleObject
sem _wait
释放
ReleaseMutex
sem _post
试图等待
WaitForSingleObject
sem _trywait
销毁
CloseHandle
sem_destroy
1.
互斥量用于线程的互斥,信号量用于线程的同步
。
——
这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
2.
互斥量无法保证线程对资源的有序访问,信号量可以。
是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。(
cute
:好比一个别墅,同时只能卖个一个人。这个人可以在门上加上任意多的锁(申请多次),但是锁必须由这个人打开,因为只有他掌握着钥匙。如果别的人真的想控制这个别墅的大门,则它首先应该把这个别墅买下来(别墅的主人放弃所有权))
是指在互斥的基础上(大多数情况)
,通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
(
cute
:相当于图书馆阅览室的书卡,你申请的时候
-1
,另一个人还的时候则可以
+1
,我们都可以修改书卡的当前可用数目,这个权利是不独属于任何人的。)
3.
互斥量值只能为
0/1
,信号量值可以为非负整数。
也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。
4.
互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到
。
理解互斥量和信号量 作者: JuKevin
互斥量
(Mutex)
信号量
二进制信号量
(binary semaphore)
:
整型信号量(
integer semaphore)
记录型信号量(
record semaphore)
互斥量和信号量的区别
互斥
同步