一、
1、互斥鎖總是必須由給其上鎖的線程解鎖,信號量的掛出確不必由執行過它的等待操作的同一線程執行。
生產者與消費者偽代碼
2、互斥鎖要么被鎖住,要么被解鎖(二值狀態,類似於二值信號量)
3、既然信號量有一個與之關聯的狀態(它的數值),那么信號量的掛出操作總是被記住。然而當向一個條件變量發送信號時,如果沒有線程等待在該條件變量上,那么信號將丟失。
ps:提供信號量的原因是,在進程間同步的情況下,若沒有涉及到共享內存區時,需要使用信號量。
二、
1、posix提供量中信號量:有名信號量和基於內存的信號量,后者被稱為無名信號量。
有名信號量如下圖所示:
內存信號量(無名信號量)如下圖所示:
三、有名信號量
sem_open:創建一個新的有名信號量或者打開一個已經存在的有名信號量。有名信號量既可用於線程間同步,也可用於進程間同步。
頭文件:#include <semaphore.h> 函數原型:sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value); 參數: name 信號量的外部名字 oflag 選擇創建或打開一個現有的信號量 mode 權限位 value 信號量初始值
sem_close用於關閉打開着的信號量:
#include <semaphore.h>
int sem_close(sem_t *sem)
sem_unlink將有名信號量從系統中刪除
#include <semaphore.h> int sem_unlink(const char *name)
#include <semaphore.h> int sem_wait(sem_t *sem); int sem_trywait(sem_t *sem);
sem_post是給信號量的值加上一個“1”,它是一個“原子操作”---即同時對同一個信號量做加“1”操作的兩個線程是不會沖突的;
#include <semaphore.h>
int sem_post(sem_t *sem);
sem_getvalue,計算機術語,是把 sem 指向的信號量當前值放置在 sval 指向的整數上。 如果有一個或多個進程或線程當前正在使用 sem_wait(3) 等待信號量,POSIX.1-2001 允許返回兩種結果在 sval 里:要么返回 0;要么返回一個負值,它的絕對等於當前正在 sem_wait(3) 里阻塞的進程和線程數。Linux 選擇了前面的行為(返回零)。
#include <semaphore.h> int sem_getvalue(sem_t *sem,int *sval);
posix有名信號量至少是隨內核持續性的,因此可以跨多個進程操作他們。
四、無名信號量
之前的內容處理的是posix有名信號量的內容,這些信號量是由一個name參數標識的,它通常指代文件系統中的某個文件。然而posix也提供了基於內存的信號量。
int sem_init(sem_t *sem, int pshared, unsigned int value);
如果 pshared 是0,那么初始化的信號量是在同一個進程的各個線程間共享的。
如果 pshared 是非零值,那么信號量將在進程之間共享,並且應該定位共享內存區域(見 shm_open(3)、mmap(2) 和 shmget(2))。因為通過 fork(2)
創建的孩子繼承其父親的內存映射,因此它也可以見到這個信號量。所有可以訪問共享內存區域的進程都可以用 sem_post(3)、sem_wait(3) 等等操作信號量。
初始化一個已經初始的信號量其結果未定義。 參數 sem :指向信號量對象 pshared : 指明信號量的類型。不為0時此信號量在進程間共享,否則只能為當前進程的所有線程共享。 value : 指定信號量值的大小 返回值 sem_init() 成功時返回 0;錯誤時,返回 -1,並把 errno 設置為合適的值。 錯誤 EINVAL value 超過 SEM_VALUE_MAX。 ENOSYS pshared 非零,但系統還沒有支持進程共享的信號量。
摧毀信號量:
#include <semaphore.h>
int sem_destroy(sem_t *sem);
進程間共享基於內存信號量的規則:信號量本身(其作為sem_init第一個參數的sem_t數據類型變量)必須駐留在由所有希望共享它的進程所共享的內存區中,而且sem_init的第二個參數必須是1。
在父進程中打開的任何信號量仍應在子進程中打開。如下:
sem_t *sem; sem = sem_open("sem name",O_CREATE|O_EXCL,FILE_MODE,0); if(childpid = fork() == 0) { sem_wait(sem); } else { sem_post(sem); }