互斥和同步

找了一些资料,摘录部分内容如下:

1. mutual exclusion

2. semaphore

3. mutex

4. mutex vs binary semaphore

5. synchronization

6. condition variable

7. condition variable vs semaphore

 

mutual exclusion

「it is the requirement that one thread of execution never enter its critical section at the same time that another concurrent thread of execution enters its own critical section.」@2
「The requirement of mutual exclusion was first identified and solved by Edsger W. Dijkstra in his seminal 1965 paper titled Solution of a problem in concurrent programming control.」@2
「Dijkstra's famous "Cooperating Sequential Processes (EWD123) was written in 1965, presented at a 1966 NATO Summer School, and published in a 1968 book Programming Languages, edited by F. Genuys. See .」@5
「Back in 1965, Edsger Dijkstra ... introduced the concept of a binary semaphore into modern programming to address possible race conditions in concurrent programs. His very simple idea was to use a pair of function calls to the operating system to indicate entering and leaving a critical region.」@1

Dijkstra最初提出的semaphore是用于实现互斥。


semaphore

「A variant of Dijkstra's semaphore was put forward by another Dutchman, Dr. Carel S. Scholten. In his proposal the semaphore can have an initial value (or count) greater than one. This enables building programs where more than one resource is being managed in a given critical region.」@1
「Scholten's semaphore is referred to as the General or Counting Semaphore, Dijkstra's being known as the Binary Semaphore.」@1

最初提出的Counting Semaphore用于临界区中有多份资源的情况。至于进入临界区后如何确定哪份资源可用,不是由Counting Semaphore负责的,参考@5 bathroom的例子和@6 Adam Davis进一步的讨论「A semaphore is the wrong tool to protect several of the essentially same resource, but this is how many people think of it and use it. The bouncer analogy is distinctly different - there aren't several of the same type of resource, instead there is one resource which can accept multiple simultaneous users.」

「Counting semaphores are not used to enforce mutual exclusion because they enable multiple threads of execution in the critical region at once. Instead, they are used to enforce limits in certain code.They are not used much in the kernel.」@lkd chap.10
「"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」@

这两个使用情景中限制的是并发进入临界区的线程数量,临界资源只有一份。而最初提出的使用情景是临界区中有多份相同的临界资源。

小结:

「user cases: (1) mutual exclusive like( mutex), (2) counting semaphore to control access to a pool of a shared resources, (3) scheduling constraint ( need wait(), and value can be negative, but some implementations does not allow negative value). cause one thread to wait for a specific action to be signaled from another thread ( execution order).」@

+(2.5)限制并发进入临界区的线程数量

(1)、(2)和(2.5)的线程模型是thread(){take(); ...; give()}[N];(3)的线程模型是thread_give()[M]+thread_take()[N],后者semaphore用于同步,而不是互斥。


mutex

「To address the problems associated with semaphore, a new concept was developed during the late 1980's. I have struggled to find it's first clear definition, but the major use of the term mutex (another neologism based around MUTual EXclusion) appears to have been driven through the development of the common programming specification for UNIX based systems. In 1990 this was formalised by the IEEE as standard IEEE Std 1003.1 commonly known as POSIX.」@3
「POSIX.1 defines four types: PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_DEFAULT」@APUE section 12.4.1 @TLPI section 30.1.7


mutex vs binary semaphore

「Dijkstra's revolutionary, safe-and-scalable Semaphore was applied in both critical section protection and signaling. And thus the confusion began. However, it later became obvious to operating system developers, after the appearance of the priority-based preemptive RTOS (e.g., VRTX, ca. 1980), publication of academic papers establishing RMA and the problems caused by priority inversion, and a paper on priority inheritance protocols in 1990, 3 it became apparent that mutexes must be more than just semaphores with a binary counter.」@5

前面提到semaphore最初用于互斥

「Until recently, the only sleeping lock in the kernel was the semaphore. Most users of semaphores instantiated a semaphore with a count of one and treated them as a mutual exclusion lock—a sleeping version of the spin lock. Unfortunately, semaphores are rather generic and do not impose many usage constraints.This makes them useful for managing exclusive access in obscure situations, such as complicated dances between the kernel and userspace. But it also means that simpler locking is harder to do, and the lack of enforced rules makes any sort of automated debugging or constraint enforcement impossible. Seeking a simpler sleeping lock, the kernel developers introduced the mutex.Yes, as you are now accustomed to, that is a confusing name. Let's clarify.The term “mutex” is a generic name to refer to any sleeping lock that enforces mutual exclusion, such as a semaphore with a usage count of one. In recent Linux kernels, the proper noun “mutex” is now also a specific type of sleeping lock that implements mutual exclusion.That is, a mutex is a mutex.」@lkd chap.10
「Semaphores Versus Mutexes Mutexes and semaphores are similar. Having both in the kernel is confusing.Thankfully, the formula dictating which to use is quite simple: Unless one of mutex's additional constraints prevent you from using them, prefer the new mutex type to semaphores.When writing new code, only specific, often low-level, uses need a semaphore. Start with a mutex and move to a semaphore only if you run into one of their constraints and have no other alternative.」@lkd chap.10

在linux上,一般在线程中使用mutex进行互斥,不使用semaphore;进程间互斥可以使用mutex进行互斥,「If the process-shared mutex attribute is set to PTHREAD_PROCESS_SHARED,a mutex allocated from a memory extent shared between multiple processes may be used for synchronization by those processes.」@APUE section 12.4

「A mutex is really a semaphore with value 1? No, no and no again.」@1
「The mutex is similar to the principles of the binary semaphore with one significant difference: the principle of ownership. Ownership is the simple concept that when a task locks (acquires) a mutex only it can unlock (release) it.」@3
「The concept of ownership enables mutex implementations to address the problems discussed in part 1:」@3
「the inherent dangers associated with using the semaphore: 1. Accidental release (an inherent weakness of using the counting semaphore as a binary semaphore) 2. Recursive deadlock 3. Task-Death deadlock 4. Priority inversion 5. Semaphore as a signal (Due to ownership a mutex cannot be used for synchronization due to lock/unlock pairing. This makes the code cleaner by not confusing the issues of mutual exclusion with synchronization)」@1
「In object terminology we can observe that : observation.1 Semaphore contains mutex observation.2 Mutex is not semaphore and semaphore is not mutex. There are some semaphores that will act as if they are mutex, called binary semaphores, but they are freaking NOT mutex. There is a special ingredient called Signaling (posix uses condition_variable for that name), required to make a Semaphore out of mutex. Think of it as a notification-source. If two or more threads are subscribed to same notification-source, then it is possible to send them message to either ONE or to ALL, to wakeup. There could be one or more counters associated with semaphores, which are guarded by mutex. The simple most scenario for semaphore, there is a single counter which can be either 0 or 1. This is where confusion pours in like monsoon rain. A semaphore with a counter that can be 0 or 1 is NOT mutex. Mutex has two states (0,1) and one ownership(task). Semaphore has a mutex, some counters and a condition variable. Now, use your imagination, and every combination of usage of counter and when to signal can make one kind-of-Semaphore. Single counter with value 0 or 1 and signaling when value goes to 1 AND then unlocks one of the guy waiting on the signal == Binary semaphore Single counter with value 0 to N and signaling when value goes to less than N, and locks/waits when values is N == Counting semaphore Single counter with value 0 to N and signaling when value goes to N, and locks/waits when values is less than N == Barrier semaphore (well if they don‘t call it, then they should.) Now to your question, when to use what. (OR rather correct question version.3 when to use mutex and when to use binary-semaphore, since there is no comparison to non-binary-semaphore.) Use mutex when 1. you want a customized behavior, that is not provided by binary semaphore, such are spin-lock or fast-lock or recursive-locks. You can usually customize mutexes with attributes, but customizing semaphore is nothing but writing new semaphore. 2. you want lightweight OR faster primitive Use semaphores, when what you want is exactly provided by it. If you don‘t understand what is being provided by your implementation of binary-semaphore, then IMHO, use mutex.」@ Ajeet Ganga
「The correct use of a semaphore is for signaling from one task to another. A mutex is meant to be taken and released, always in that order, by each task that uses the shared resource it protects. By contrast, tasks that use semaphores either signal or wait—not both.」@5
「mutexes should be used to protect shared resources, while semaphores should be used for signaling.」@6
「Mutual Exclusion semaphores are used to protect shared resources...A Binary semaphore should be used for Synchronization」@ Benoit
「companies like Wind River Systems redefining a mutex as a “Mutual-Exclusion Semaphore”」@1
「a mutex is locking mechanism used to synchronize access to a resource. ..Semaphore is signaling mechanism.」@ 「a mutex cannot be used for synchronization」@3

以上所说的signaling和synchronization是一个意思。


synchronization

「the term synchronization is often misused in the context of mutual exclusion」@1
「Synchronization is, by definition “To occur at the same time; be simultaneous”. Synchronization between tasks is where, typically, one task waits to be notified by another task before it can continue execution (unilateral rendezvous). A variant of this is either task may wait, called the bidirectional rendezvous.」@1

将synchronization和mutual exclusion的概念分开来更易于理解和开发。打个比方,餐厅中,洗菜工之间以及厨师之间是互斥关系,洗菜工和厨师之间是同步关系。但很多地方将后者归入前者。

「进程互斥是指若干进程因相互争夺独占型资源而产生的竞争制约关系。」「进程同步是指为完成共同任务的并发进程基于某个条件来协调其活动,因为需要在某些位置上排定执行的先后次序而等待、传递信号或消息所产生的协作制约关系。」 「进程互斥关系是一种特殊的进程同步关系,即逐次使用互斥共享资源,也是对进程使用资源的次序的一种协调。」 @《操作系统教程/孙钟秀(第四版)》3.1.3节
「Process synchronization refers to the idea that multiple processes are to join up or handshake at a certain point, in order to reach an agreement or commit to a certain sequence of action......Processes' access to critical section is controlled by using synchronization techniques...Another synchronization requirement which needs to be considered is the order in which particular processes or threads should be executed.」@4

维基百科介绍的synchronization包含了mutual exclusion

APUE section 11.6 Thread Synchronization包含mutex,condition variable,barrier等

lkd chap.10 Kernel Synchronization Methods包含semaphore,mutex,completion variable,barrier等。它比较了semaphore和mutex,但没有比较semaphore和completion variable。completion variable用于“狭义”上的synchronization,「Using completion variables is an easy way to synchronize between two tasks in the kernel when one task needs to signal to the other that an event has occurred.」

TLPI chap.10 THREADS: THREAD SYNCHRONIZATION主要介绍了Protecting Accesses to Shared Variables: Mutexes和Signaling Changes of State: Condition Variables。不妨理解为后者才是真正意义上的synchronization.

TLPI chap.40 INTERPROCESS COMMUNICATION OVERVIEW section 43.3 Synchronization Facilities包含了Semaphores,File locks,Mutexes and condition variables。值得注意的是,作者将IPC分为communication,synchronization,signal三类,将System V IPC三件套中的semaphore和POSIX semaphore一起归入synchronization中。这样划分更合理。

我认为应该把广义上的synchronization称为coordination,后者包含mutual exclusion和synchronization。


condition variable

@TLPI section 30.2.2


condition variable vs semaphore

「What is important to understand is that the semaphore counter keeps track of the number of tasks that do not have to block, i.e., they can make progress. Tasks block, and add themselves to the semaphore's list only when the counter is zero.」@6 aspen100
「A condition variable holds no state information. It is simply a mechanism for communicating information about the application's state. If no thread is waiting on the condition variable at the time that it is signaled, then the signal is lost. A thread that later waits on the condition variable will unblock only when the variable is signaled once more.」@TLPI section 30.2.2

:

「Condition variable is essentially a wait-queue...Semaphore is essentially a counter + a mutex + a wait queue...semaphore can be treated as a more sophisticated structure than condition variable, while the latter is more lightweight and flexible.」@cucufrog
「Semaphores can be used to implement exclusive access to variables, however they are meant to be used for synchronization. Mutexes, on the other hand, have a semantics which is strictly related to mutual exclusion: only the process which locked the resource is allowed to unlock it. Unfortunately you cannot implement synchronization with mutexes, that's why we have condition variables. Also notice that with condition variables you can unlock all the waiting threads in the same instant by using the broadcast unlocking. This cannot be done with semaphores.」@Dacav
「to implement barrier synchronization you would not be able to use a semaphore.But a condition variable is ideal.」@Danielle

参考前面Ajeet Ganga提到的barrier semaphore

「Semaphore is used to control the number of threads executing. There will be fixed set of resources. 」@berkay

这种情景使用semaphore很贴切。



「Semaphores vs. Condition Variables 1. Up differs from Signal in that: --Signal has no effect if no thread is waiting on the condition. ----Condition variables are not variables! They have no value! --Up has the same effect whether or not a thread is waiting. ----Semaphores retains a "memory" of calls to Up. 2. Down differs from Wait in that: --Down checks the condition and blocks only if necessary. ----no need to recheck the condition after returning from Down ----wait condition is defined internally, but is limited to a counter --Wait is explicit: it does not check the condition, ever. ----condition is defined externally and protected by integrated mutex」@
「Semaphores using Condition Variables. This constitutes a proof that mutexes and condition variables are at least as powerful as semaphores.」 @


来源:

1. https://blog.feabhas.com/2009/09/mutex-vs-semaphores-%e2%80%93-part-1-semaphores/

2.

3. https://blog.feabhas.com/2009/09/mutex-vs-semaphores-%e2%80%93-part-2-the-mutex/

4. )

5.

6.

7. APUE(Advanced Programming in the Unix Environment) 3ed

8. TLPI(The Linux Programming Interface)

9. lkd(linux kernel development)3ed

posted @ 2017-08-10 15:41  AlbumCover  阅读(435)  评论(0编辑  收藏  举报