理解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.
From:http://www.cnblogs.com/shangdawei/p/3520102.html