Semaphore 和 Mutex
mutex和semaphore有什么区别呢?
mutex是用作互斥的,而semaphore是用作同步的。
也就是说,mutex的初始化一定是为1,而semaphore可以是任意的数,
所以如果使用mutex,那第一个进入临界区的进程一定可以执行,而其他的进程必须等待。
而semaphore则不一定,如果一开始初始化为0,则所有进程都必须等待。
同时mutex和semaphore还有一个区别是,获得mutex的进程必须亲自释放它,而semaphore则可以一个进程获得,另一个进程释放。
http://www.cppblog.com/martin/archive/2009/03/18/hello.html
mutex与semaphore的区别
"互斥(mutext)和旗语(semaphore)之间有什么不同?"这样的问题简短而有力,但要回答却相当困难.
即使有经验的实时操作系统(RTOS)用户在区别如何正确使用mutex和semaphore时也存在着困难.
但这一点很不幸而且很危险,因为无任这两种原生RTOS中的哪一种被错误使用,都会导致嵌入式系统出现意想不到的错误,特别是这些系统为有关生命安全的产品时.
有关mutex和semaphore的荒诞说法是它们是相似的,甚至是可以互换的.
正确的事实是尽管mutex和semaphore在它们的执行上有相似之处,但是我们还是应该在使用它们时加以区别对待.
最普遍(但也是不正确)的答案是:mutex和semphore非常相似,它们只有一个区别,那就是semaphores的计数可以超过1.
差不多所有的工程师都能正确的理解:mutex是一个二进制标志,可以通过它来确保执行流在代码关键区(critical section of code)互相排斥,从而对共享资源加一保护.
但当他们被要求进一步回答如何使用"计算方法semaphore"的方式时,大部分工程师的回答就如同教科书书一般的刻板---semaphore用于保护多重同类资源.
通过类比办法,我们很容易解释为什么"多重资源"场景是有缺陷的.如果你认为一个mutex是由操作系统拥有的关键值的话,我们可以很容易地将个别的mutex比喻是城市咖啡店中一间浴室的钥匙.
如果你想使用浴室,却找不到钥匙,你就必须在一个队列中等候.同样地,mutex则协串行化多项任务,以取得全域资源的共享,并且为等待队列中的任务分配一个静候其循序渐进的位置.
但这种简单的资源保护协议并不使用于两间相同浴室的情况.如果把一个semaphore概括为一个mutex,使其能保护两个或更多相同的资源,
那么在我们的比喻中,它就象是放着两把相同钥匙的蓝子,你可以用任何一把打开任何一扇浴室的门.
因此,semaphore本身并不能解决多个相同资源的问题.咖啡店中的客人可能只知道有一把钥匙,但并不知道哪间浴室可用.
如果你试图以此方式使用semaphore,你将会发现需要更多的状态信息---它们通常是由不同的mutex所保护的共享资源.
正确使用semaphore是为了使信号从一项任务传至另一项任务.
mutex意味着取得与释放,使用受保护共享资源的每一次任务都是以这样的顺序进行.
相比之下,使用semaphore的任务通常不是发送信号,就是进入等待状态,不可能同时发生.
例如,任务1可能包含程序代码,当按下"电源"(power)按钮时,即可提出(如发送信号或增量)一个特别的semaphore;
任务2则依据相同的semaphore而用于唤醒显示器. 在这种情况下,其中一项任务是信号的生产者,另一项任务是信号的消费者.
用一个例子来做总结,首先展示如何使用mutex:
/* Task 1 */
mutexWait(mutex_mens_room);
// Safely use shared resource
mutexRelease(mutex_mens_room);
/* Task 2 */
mutexWait(mutex_mens_room);
// Safely use shared resource
mutexRelease(mutex_mens_room);
相应地,你总是采用下列方法使用semaphore:
/* Task 1 - Producer */
semPost(sem_power_btn); // Send the signal
/* Task 2 - Consumer */
semPend(sem_power_btn); // Wait for signal
重要的是,semaphores可以被interrupt service routine(ISR)中断服务程序用来向task发送信号.
发送一个semaphore是一个非阻塞的RTOS行为,并且ISR安全.
因为这种技术排除了在task级别的为了是中断不使能而引起的错误的可能性,
从ISR中发出信号是一种使嵌入式软件更加可靠的设计方式.
http://ousysrobin.blog.hexun.com/57137773_d.html
理解Semaphore和Mutex
Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。
一般的用法是用于串行化对critical section代码的访问,保证这段代码不会被并行的运行。
Semaphore是一件可以容纳N人的房间,如果人不满就可以进去,如果人满了,就要等待有人出来。
对于N=1的情况,称为binary semaphore。一般的用法是,用于限制对于某一资源的同时访问。
Binary semaphore与Mutex的差异:
在有的系统中Binary semaphore与Mutex是没有差异的。在有的系统上,主要的差异是mutex一定要由获得锁的进程来释放。
而semaphore可以由其它进程释 放(这时的semaphore实际就是个原子的变量,大家可以加或减),因此semaphore可以用于进程间同步。
Semaphore的同步功能是所有 系统都支持的,而Mutex能否由其他进程释放则未定,
因此建议mutex只用于保护critical section。而semaphore则用于同步或者保护某变量。
关于semaphore和mutex的区别,网上有著名的厕所理论(http://koti.mbnet.fi/niclasw/MutexSemaphore.html):
The Toilet Example (c) Copyright 2005, Niclas Winquist ;)
http://www.cnblogs.com/xiangshancuizhu/p/3305609.html
Mutex:
Is a key to a toilet. One person can have the key - occupy the toilet - at the time.
When finished, the person gives (frees) the key to the next person in the queue.
mutex是厕所钥匙,一次只能一人那着这把钥匙去厕所。结束了,这个人把钥匙给队列中的下一个人。
Officially: “Mutexes are typically used to serialise access to a section of re-entrant code
that cannot be executed concurrently by more than one thread. A mutex object only
allows one thread into a controlled section, forcing other threads which attempt to
gain access to that section to wait until the first thread has exited from that section.”
Ref: Symbian Developer Library
Semaphore:
Is the number of free identical toilet keys. Example, say we have four toilets with identical locks and keys.
The semaphore count - the count of keys - is set to 4 at beginning (all four toilets are free),
then the count value is decremented as people are coming in.
If all toilets are full, ie. there are no free keys left, the semaphore count is 0.
Now, when eq. one person leaves the toilet, semaphore is increased to 1 (one free key),
and given to the next person in the queue.
信号量是一个自由的官方厕所钥匙,我们有四个厕所,他们的锁和钥匙是一样的。
信号量开始设置为4,表示4个厕所是自由滴,如果一个人进去了,数量就-1.
如果厕所满了,钥匙数目就为0,信号量数目这时也是0.如果一个人离开厕所,信号量+1,队列中的下一个人可以用啦!
Officially: “A semaphore restricts the number of simultaneous users of a shared resource up to a maximum number.
Threads can request access to the resource (decrementing the semaphore), and can signal that they have finished
using the resource (incrementing the semaphore).” Ref: Symbian Developer Library
所以,mutex就是一个binary semaphore (值就是0或者1)。但是他们的区别又在哪里呢?主要有两个方面:
* 初始状态不一样:mutex的初始值是1(表示锁available),而semaphore的初始值是0(表示unsignaled的状态)。
随后的操 作基本一样。mutex_lock和sem_post都把值从0变成1,mutex_unlock和sem_wait都把值从1变成0(如果值是零就等 待)。
初始值决定了:虽然mutex_lock和sem_wait都是执行V操作,但是sem_wait将立刻将当前线程block住,直到有其他线程 post;
mutex_lock在初始状态下是可以进入的。
* 用法不一样(对称 vs. 非对称):这里说的是“用法”。Semaphore实现了signal,但是mutex也有signal
(当一个线程lock后另外一个线程 unlock,lock住的线程将收到这个signal继续运行)。
在mutex的使用中,模型是对称的。unlock的线程也要先lock。
而 semaphore则是非对称的模型,对于一个semaphore,只有一方post,另外一方只wait。
就拿上面的厕所理论来说,mutex是一个钥 匙不断重复的使用,传递在各个线程之间,
而semaphore择是一方不断的制造钥匙,而供另外一方使用(另外一方不用归还)。
(A mutex is really a semaphore with value 1.) ????
http://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
Mutexes are binary semaphores that include a priority inheritance mechanism.
Whereas binary semaphores are the better choice for implementing synchronisation
(between tasks or between tasks and an interrupt),
mutexes are the better choice for implementing simple mutual exclusion (hence 'MUT'ual 'EX'clusion).
When used for mutual exclusion the mutex acts like a token that is used to guard a resource.
When a task wishes to access the resource it must first obtain ('take') the token.
When it has finished with the resource it must 'give' the token back -
allowing other tasks the opportunity to access the same resource.
Mutexes use the same semaphore access API functions so also permit a block time to be specified.
The block time indicates the maximum number of 'ticks' that a task should enter the Blocked state
when attempting to 'take' a mutex if the mutex is not immediately available.
Unlike binary semaphores however - mutexes employ priority inheritance.
This means that if a high priority task blocks while attempting to obtain a mutex (token)
that is currently held by a lower priority task, then the priority of the task holding the token
is temporarily raised to that of the blocking task.
This mechanism is designed to ensure the higher priority task is kept in the blocked state
for the shortest time possible, and in so doing minimise the 'priority inversion' that has already occurred.
Priority inheritance does not cure priority inversion! It just minimises its effect in some situations.
Hard real time applications should be designed such that priority inversion does not happen in the first place.
http://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html
Binary semaphores are used for both mutual exclusion and synchronisation purposes.
Binary semaphores and mutexes are very similar but have some subtle differences:
Mutexes include a priority inheritance mechanism, binary semaphores do not.
This makes binary semaphores the better choice for implementing synchronisation
(between tasks or between tasks and an interrupt), and
mutexes the better choice for implementing simple mutual exclusion.
The description of how a mutex can be used as a mutual exclusion mechanism holds equally for binary semaphores.
This sub section will only describe using binary semaphores for synchronisation.
Semaphore API functions permit a block time to be specified.
The block time indicates the maximum number of 'ticks' that
a task should enter the Blocked state when attempting to 'take' a semaphore,
should the semaphore not be immediately available.
If more than one task blocks on the same semaphore then the task with
the highest priority will be the task that is unblocked the next time the semaphore becomes available.
Think of a binary semaphore as a queue that can only hold one item.
The queue can therefore only be empty or full (hence binary).
Tasks and interrupts using the queue don't care what the queue holds -
they only want to know if the queue is empty or full.
This mechanism can be exploited to synchronise (for example) a task with an interrupt.
Consider the case where a task is used to service a peripheral.
Polling the peripheral would be wasteful of CPU resources, and prevent other tasks from executing.
It is therefore preferable that the task spends most of its time in the Blocked state (allowing other tasks to execute)
and only execute itself when there is actually something for it to do.
This is achieved using a binary semaphore by having the task Block while attempting to 'take' the semaphore.
An interrupt routine is then written for the peripheral that just 'gives' the semaphore when the peripheral requires servicing.
The task always 'takes' the semaphore (reads from the queue to make the queue empty), but never 'gives' it.
The interrupt always 'gives' the semaphore (writes to the queue to make it full) but never takes it.
The source code provided on the xSemaphoreGiveFromISR() documentation page should make this clearer.
Task prioritisation can be used to ensure peripherals get services in a timely manner
- effectively generating a 'differed interrupt' scheme.
An alternative approach is to use a queue in place of the semaphore.
When this is done the interrupt routine can capture the data associated
with the peripheral event and send it on a queue to the task.
The task unblocks when data becomes available on the queue,
retrieves the data from the queue, then performs any data processing that is required.
This second scheme permits interrupts to remain as short as possible, with all post processing instead occurring within a task.
See the Semaphores/Mutexes section of the user documentation for a list of semaphore related API functions.
Searching the files in the FreeRTOS/Demo/Common/Minimal directory will reveal multiple examples of their usage.
Note that interrupts must NOT use API functions that do not end in "FromISR" .
Using a semaphore to synchronise a task with an interrupt.
The interrupt only ever 'gives' the semaphore,
while the task only ever 'takes' the semaphore.
http://stackoverflow.com/questions/62814/difference-between-binary-semaphore-and-mutex
Their synchronization semantics are very different:
- mutexes allow serialization of access to a given resource i.e. multiple threads wait for a lock,
one at a time and as previously said, the thread owns the lock until it is done:
only this particular thread can unlock it. - a binary semaphore is a counter with value 0 and 1: a task blocking on it until any task does a sem_post.
The semaphore advertises that a resource is available, and it provides the mechanism
to wait until it is signaled as being available.
As such one can see a mutex as a token passed from task to tasks
and a semaphore as traffic red-light (it signals someone that it can proceed).
On Windows, there are two differences between mutexes and binary semaphores:
-
A mutex can only be released by the thread which has ownership,
i.e. the thread which previously called the Wait function, (or which took ownership when creating it).
A semaphore can be released by any thread. -
A thread can call a wait function repeatedly on a mutex without blocking.
However, if you call a wait function twice on a binary semaphore
without releasing the semaphore in between, the thread will block.
In windows the difference is as below.
MUTEX: process which successfully executes wait has to execute asignal and vice versa.
BINARY SEMAPHORES: Different processes can execute wait or signal operation on a semaphore.
A Mutex controls access to a single shared resource.
It provides operations to acquire() access to that resource and release() it when done.
A Semaphore controls access to a shared pool of resources.
It provides operations to Wait() until one of the resources in the pool becomes available,
and Signal() when it is given back to the pool.
When number of resources a Semaphore protects is greater than 1, it is called a Counting Semaphore.
When it controls one resource, it is called a Boolean Semaphore.
A boolean semaphore is equivalent to a mutex.
Thus a Semaphore is a higher level abstraction than Mutex.
A Mutex can be implemented using a Semaphore but not the other way around.
http://www.geeksforgeeks.org/mutex-vs-semaphore/
Strictly speaking, a mutex is locking mechanism used to synchronize access to a resource.
Only one task (can be a thread or process based on OS abstraction) can acquire the mutex.
It means there will be ownership associated with mutex, and only the owner can release the lock (mutex).
Semaphore is signaling mechanism (“I am done, you can carry on” kind of signal).
For example, if you are listening songs (assume it as one task) on your mobile
and at the same time your friend called you, an interrupt will be triggered upon
which an interrupt service routine (ISR) will signal the call processing task to wakeup.
http://www.geeksforgeeks.org/mutex-vs-semaphore/
Mutex vs Semaphore
What are the differences between Mutex vs Semaphore?
When to use mutex and when to use semaphore?
Concrete understanding of Operating System concepts is required to design/develop smart applications.
Our objective is to educate the reader on these concepts and learn from other expert geeks.
As per operating system terminology, the mutex and semaphore are kernel resources that provide synchronization services
(also called as synchronization primitives).
Why do we need such synchronization primitives? Won’t be only one sufficient?
To answer these questions, we need to understand few keywords.
Please read the posts on atomicity and critical section.
We will illustrate with examples to understand these concepts well, rather than following usual OS textual description.
The producer-consumer problem:
Note that the content is generalized explanation. Practical details will vary from implementation.
Consider the standard producer-consumer problem.
Assume, we have a buffer of 4096 byte length.
A producer thread will collect the data and writes it to the buffer.
A consumer thread will process the collected data from the buffer.
Objective is, both the threads should not run at the same time.
Using Mutex:
A mutex provides mutual exclusion, either producer or consumer can have the key (mutex) and proceed with their work.
As long as the buffer is filled by producer, the consumer needs to wait, and vice versa.
At any point of time, only one thread can work with the entire buffer. The concept can be generalized using semaphore.
Using Semaphore:
A semaphore is a generalized mutex. In lieu of single buffer, we can split the 4 KB buffer into four 1 KB buffers (identical resources).
A semaphore can be associated with these four buffers. The consumer and producer can work on different buffers at the same time.
Misconception:
There is an ambiguity between binary semaphore and mutex.
We might have come across that a mutex is binary semaphore.
But they are not! The purpose of mutex and semaphore are different.
May be, due to similarity in their implementation a mutex would be referred as binary semaphore.
Strictly speaking, a mutex is locking mechanism used to synchronize access to a resource.
Only one task (can be a thread or process based on OS abstraction) can acquire the mutex.
It means there will be ownership associated with mutex, and only the owner can release the lock (mutex).
Semaphore is signaling mechanism (“I am done, you can carry on” kind of signal).
For example, if you are listening songs (assume it as one task) on your mobile and
at the same time your friend called you, an interrupt will be triggered upon
which an interrupt service routine (ISR) will signal the call processing task to wakeup.
General Questions:
1. Can a thread acquire more than one lock (Mutex)?
Yes, it is possible that a thread will be in need of more than one resource, hence the locks.
If any lock is not available the thread will wait (block) on the lock.
2. Can a mutex be locked more than once?
A mutex is a lock. Only one state (locked/unlocked) is associated with it.
However, a recursive mutex can be locked more than once (POSIX complaint systems),
in which a count is associated with it, yet retains only one state (locked/unlocked).
The programmer must unlock the mutex as many number times as it was locked.
3. What will happen if a non-recursive mutex is locked more than once.
Deadlock. If a thread which had already locked a mutex, tries to lock the mutex again,
it will enter into the waiting list of that mutex, which results in deadlock.
It is because no other thread can unlock the mutex.
An operating system implementer can exercise care in identifying the owner of mutex
and return if it is already locked by same thread to prevent deadlocks.
4. Are binary semaphore and mutex same?
No. We will suggest to treat them separately, as it was explained signalling vs locking mechanisms.
But a binary semaphore may experience the same critical issues (e.g. priority inversion) associated with mutex.
We will cover these later article.
A programmer can prefer mutex rather than creating a semaphore with count 1.
5. What is a mutex and critical section?
Some operating systems use the same word critical section in the API.
Usually a mutex is costly operation due to protection protocols associated with it.
At last, the objective of mutex is atomic access.
There are other ways to achieve atomic access like disabling interrupts
which can be much faster but ruins responsiveness.
The alternate API makes use of disabling interrupts.
6. What are events?
The semantics of mutex, semaphore, event, critical section, etc… are same.
All are synchronization primitives. Based on their cost in using them they are different.
We should consult the OS documentation for exact details.
7. Can we acquire mutex/semaphore in an Interrupt Service Routine?
An ISR will run asynchronously in the context of current running thread.
It is not recommended to query (blocking call) the availability of synchronization primitives in an ISR.
The ISR are meant be short, the call to mutex/semaphore may block the current running thread.
However, an ISR can signal a semaphore or unlock a mutex.
8. What we mean by “thread blocking on mutex/semaphore” when they are not available?
Every synchronization primitive will have waiting list associated with it.
When the resource is not available, the requesting thread will be moved from the running list of processor
to the waiting list of the synchronization primitive.
When the resource is available, the higher priority thread on the waiting list
will get resource (more precisely, it depends on the scheduling policies).
9. Is it necessary that a thread must block always when resource is not available?
Not necessarily. If the design is sure ‘what has to be done when resource is not available‘,
the thread can take up that work (a different code branch).
To support application requirements the OS provides non-blocking API.
For example POSIX pthread_mutex_trylock() API.
When the mutex is not available the function will return immediately
where as the API pthread_mutex_lock() will block the thread till resource is available.
References:
http://www.netrino.com/node/202
http://doc.trolltech.com/4.7/qsemaphore.html
Also compare mutex/semaphores with Peterson’s algorithm and Dekker’s algorithm.
A good reference is the Art of Concurrency book. Also explore reader locks and writer locks in Qt documentation.
Exercise:
Implement a program that prints a message “An instance is running” when executed more than once in the same session.
For example, if we observe word application or Adobe reader in Windows, we can see only one instance in the task manager.
How to implement it?
Article compiled by Venki.
Please write comments if you find anything incorrect, or
you want to share more information about the topic discussed above.