Linux利用訊號量實現執行緒的同步與互斥
阿新 • • 發佈:2018-12-30
執行緒使用互斥鎖可以實現執行緒間的互斥,而互斥鎖本身就是對資源的一種標識狀態,當可以申請到鎖時說明此時資源可以使用,當申請鎖失敗時說明資源此時被其他執行緒所佔用不可使用,我們可以使用訊號量來代替互斥鎖實現。
訊號量用來表示資源數目,當一個執行緒要去訪問資源時,必須先去申請訊號量,如果可以獲取到訊號量那麼該執行緒就可以正常執行,如果獲取資源失敗那麼就需要去等待。
當一個執行緒獲取到訊號量並且執行完成後必須去釋放對應的訊號量來通知其他執行緒進行工作,也就是說使用訊號量不僅可以實現執行緒的互斥也可以實現執行緒間的同步。
訊號量的操作:
①初始化
int sem_init(sem_t *sem, int pshared, unsigned int value);
引數描述:
sem:用來標識那個訊號量,是一個sem_t型別的值
pshared:pshared為0,表示訊號量作用於同一程序下的執行緒間同步
value:訊號量的初始值
返回值:
成功返回0, 失敗返回錯誤碼
②銷燬訊號量
int sem_destroy(sem_t *sem);
引數描述:
sem:用來標識是哪個訊號量
返回值;
成功返回0,失敗返回錯誤碼
③獲得資源操作(P操作)
int sem_wait(sem_t *sem);
函式說明:
wait操作,使訊號量的值減1,如果已經是0,則該執行緒被掛起到等待佇列。
引數描述:
sem:用來標識啥事那個訊號量
返回值:
成功返回0, 失敗返回錯誤碼
int sem_trywait(sem_t *sem);
該函式與上面的函式作用一樣,不過這個函式不會將執行緒掛起等待。
④釋放資源操作(V操作)
int sem_post(sem_t *sem);
函式說明:
psot操作,使訊號量的值加1,同時喚醒等待該訊號量的執行緒。
引數描述:
sem:標識是哪個訊號量
返回值:
成功返回0, 失敗返回錯誤碼
例項:
將環形佇列設定為緩衝區,生產者每生產一個數據放入到緩衝區中,消費者每次從緩衝區中讀出一個數據。
此時需要使用兩個訊號量,一個用來表示環形佇列中空位置的數量,一個用來表示環形佇列中資料的數量。
生產者只有等到有空位置時才能生產資料,消費者只有等到有資料時才能取到資料
#include<stdio.h> #include<semaphore.h> #include<pthread.h> //用陣列模擬環形佇列 int arr[8] = {0}; int i = 0; int j = 0; //設定訊號量用來表示陣列中的空位 sem_t blank; //設定訊號量用來表示陣列中的資料 sem_t data; void *product(void *arg) { while(1) { //生產者要生產必須要有空位,不然只能等待消費者取走資料之後才能生產 sem_wait(&blank); arr[i%8] = rand()%123; printf("生產者生產完成:%d\n", arr[i%8]); i++; //當生產成功時,資料量+1 sem_post(&data); sleep(i%3); } } void *consumer(void *arg) { while(1) { //消費者要消費必須有資料,不然只能等待生產者生產出資料之後才能取走 sem_wait(&data); printf("消費者消費完成:%d\n", arr[j%8]); j++; //當消費成功時,空位量+1 sem_post(&blank); sleep(j%5); } } int main() { //最開始,有8個空位 sem_init(&blank, 0, 8); //最開始,還沒有放入資料,資料為0個 sem_init(&data, 0, 0); pthread_t thread1; pthread_t thread2; pthread_create(&thread1, NULL, &product, NULL); pthread_create(&thread2, NULL, &consumer, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); sem_destroy(&blank); sem_destroy(&data); return 0; }