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://*.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.