Mutex是一把鑰匙,一個人拿了就可進入一個房間,出來的時候把鑰匙交給隊列的第一個。一般的用法是用于串行化對critical section代碼的訪問,保證這段代碼不會被并行的運行。
Semaphore是一件可以容納N人的房間,如果人不滿就可以進去,如果人滿了,就要等待有人出來。對于N=1的情況,稱為binary semaphore。一般的用法是,用于限制對于某一資源的同時訪問。
Binary semaphore與Mutex的差異:
在有的系統(tǒng)中Binary semaphore與Mutex是沒有差異的。在有的系統(tǒng)上,主要的差異是mutex一定要由獲得鎖的進程來釋放。而semaphore可以由其它進程釋 放(這時的semaphore實際就是個原子的變量,大家可以加或減),因此semaphore可以用于進程間同步。Semaphore的同步功能是所有 系統(tǒng)都支持的,而Mutex能否由其他進程釋放則未定,因此建議mutex只用于保護critical section。而semaphore則用于保護某變量,或者同步。
關(guān)于semaphore和mutex的區(qū)別,網(wǎng)上有著名的廁所理論(http://koti.mbnet.fi/niclasw /MutexSemaphore.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.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(A mutex is really a semaphore with value 1.)
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.
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)。但是他們的區(qū)別又在哪里呢?主要有兩個方面:
* 初始狀態(tài)不一樣:mutex的初始值是1(表示鎖available),而semaphore的初始值是0(表示unsignaled的狀態(tài))。隨后的操 作基本一樣。mutex_lock和sem_post都把值從0變成1,mutex_unlock和sem_wait都把值從1變成0(如果值是零就等 待)。初始值決定了:雖然mutex_lock和sem_wait都是執(zhí)行V操作,但是sem_wait將立刻將當前線程block住,直到有其他線程 post;mutex_lock在初始狀態(tài)下是可以進入的。
* 用法不一樣(對稱 vs. 非對稱):這里說的是“用法”。Semaphore實現(xiàn)了signal,但是mutex也有signal(當一個線程lock后另外一個線程 unlock,lock住的線程將收到這個signal繼續(xù)運行)。在mutex的使用中,模型是對稱的。unlock的線程也要先lock。而 semaphore則是非對稱的模型,對于一個semaphore,只有一方post,另外一方只wait。就拿上面的廁所理論來說,mutex是一個鑰 匙不斷重復(fù)的使用,傳遞在各個線程之間,而semaphore擇是一方不斷的制造鑰匙,而供另外一方使用(另外一方不用歸還)。
前面的實驗證明,mutex確實能夠做到post和wait的功能,只是大家不用而已,因為它是“mutex”不是semaphore。
下面給出一個例子:
要讓一個thread在背景不斷的執(zhí)行,最簡單的方式就是在該thread執(zhí)行無窮回圈,如while(1) {},這種寫法雖可行,卻會讓CPU飆高到100%,因為CPU一直死死的等,其實比較好的方法是,背景平時在Sleep狀態(tài),當前景呼叫背景時,背景馬 上被喚醒,執(zhí)行該做的事,做完馬上Sleep,等待前景呼叫。當背景sem_wait()時,就是馬上處于Sleep狀態(tài),當前景sem_post() 時,會馬上換起背景執(zhí)行,如此就可避免CPU 100%的情形了。
/**//* (C) OOMusou 2006 http://oomusou.cnblogs.com Filename : pthread_create_semaphore.cpp Compiler : gcc 4.10 on Fedora 5 / gcc 3.4 on Cygwin 1.5.21 Description : Demo how to create thread with semaphore in Linux. Release : 12/03/2006 Compile : g++ -lpthread pthread_create_semaphore.cpp */ #include <stdio.h> // printf(), #include <stdlib.h> // exit(), EXIT_SUCCESS #include <pthread.h> // pthread_create(), pthread_join() #include <semaphore.h> // sem_init() sem_t binSem; void* helloWorld(void* arg); int main() { // Result for System call int res = 0; // Initialize semaphore res = sem_init(&binSem, 0, 0); if (res) { printf("Semaphore initialization failed!!\n"); exit(EXIT_FAILURE); } // Create thread pthread_t thdHelloWorld; res = pthread_create(&thdHelloWorld, NULL, helloWorld, NULL); if (res) { printf("Thread creation failed!!\n"); exit(EXIT_FAILURE); } while(1) { // Post semaphore sem_post(&binSem); printf("In main, sleep several seconds.\n"); sleep(1); } // Wait for thread synchronization void *threadResult; res = pthread_join(thdHelloWorld, &threadResult); if (res) { printf("Thread join failed!!\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } void* helloWorld(void* arg) { while(1) { // Wait semaphore sem_wait(&binSem); printf("Hello World\n"); } } |
編譯運行:
[root@localhost semaphore]# gcc semaphore.c -lpthread [root@localhost semaphore]# ./a.out In main, sleep several seconds. Hello World In main, sleep several seconds. Hello World In main, sleep several seconds. Hello World In main, sleep several seconds. Hello World |