互斥鎖:上鎖與解鎖
互斥鎖指代相互排斥,是最基本的同步形式,它可用於保護臨界取,以保證任何時刻只有一個線程在執行其中的代碼。它可以用來同步一個進程內的各個線程。如果互斥鎖存放在多個進程間共用的某個記憶體區中,它也可以用於這些進程間的同步。它實際上保護的是臨界區中被操縱的資料,也就是保護由多個線程或多個進程分享的共用資料
使用方法
lock_the_mutex(...)
臨界區
unlock_the_mutex(,,,)
在Posix中,互斥鎖聲明為具有pthread_mutex_t資料類型的變數
相關函數
#include <pthread.h>
int pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t *mutexattr) //動態建立
int pthread_mutex_destroy (pthread_mutex_t * mutex) //銷毀互斥量
int pthread_mutex_lock(pthread_mutex_t *mutex); //上鎖
int pthread_mutex_trylock(pthread_mutex_t *mutex); //非阻塞解鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex); //阻塞解鎖
如果嘗試給一個已由某個線程鎖住的互斥鎖上鎖,那麼pthread_mutex_lock將阻塞到該互斥鎖解鎖為止。pthread_mutex_trylock是對應的非阻塞函數。如果該互斥鎖已鎖住。它就返回一個EBUSY錯誤
解決生產者與消費者問題
多個生產者一個消費者,如
整數數組buff含有被生產和消費的條目(也就是共用資料),buff資料從0開始遞增
線程間的共用的全域變數
設定並發線程層級
調用pthread_setconcurrency,當我們希望多個生產者線程中每一個都有執行機會時,這個函數是必須的
命令列參數
第一個命令列參數指定生產者存放的條目數,下一個參數指定建立生產者線程的數目
具體實現代碼
#include <pthread.h>#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#define MAXNITEMS 10000#define MAXNTHREADS 20int nitems; //read-only by producer and consumerstruct {pthread_mutex_t mutex;int buff[MAXNITEMS];int nput;int nval;}shared = //initialized staticly{PTHREAD_MUTEX_INITIALIZER};void *producer(void *);void *consumer(void *);int min(int a, int b) { return a<b ? a : b; }int main(int argc, char *argv[]){int i, nthreads, count[MAXNTHREADS];pthread_t tid_produce[MAXNTHREADS], tid_consume;if(argc!=3){printf("usage: ProCon <#items> <#threads>");exit(1);}nitems = min(atoi(argv[1]), MAXNITEMS);nthreads = min(atoi(argv[2]), MAXNTHREADS);pthread_setconcurrency(nthreads);for(i=0; i<nthreads; i++){count[i] = 0;pthread_create(&tid_produce[i], NULL, producer, &count[i]);}//wait for all the producer threadsfor(i=0; i<nthreads; i++){pthread_join(tid_produce[i], NULL);printf("count[%d] = %d\n", i, count[i]);}//start, then wait for the consumer threadpthread_create(&tid_consume, NULL, consumer, NULL);pthread_join(tid_consume, NULL);return 0;}void *producer(void * arg){for(; ; ){pthread_mutex_lock(&shared.mutex);if(shared.nput >= nitems){pthread_mutex_unlock(&shared.mutex);return (NULL);//array is full, we're done}shared.buff[shared.nput] = shared.nval;shared.nput++;shared.nval++;pthread_mutex_unlock(&shared.mutex);*((int *)arg) += 1;}}void *consumer(void *arg){int i;for(i=0; i<nitems; i++){if(shared.buff[i]!=i){printf("buff[%d] = %d\n", i, shared.buff[i]);}}return NULL;}
代碼解釋
39-42行用來建立消費者線程,每個線程執行producer函數,在tid_produce數組中儲存每個線程的線程ID。等待所有生產者線程結束後,再啟動消費者線程。在生產者線程結束的同時輸出每個線程的計數值,即線程的執行次數。
注意:count元素的增加不屬於臨界區,因為每個線程有各自的計數器。
運行結果如下
如果去掉互斥鎖的話,結果就會輸出buff的錯誤值(當items比較大小),
我在ubuntu上的測試結果 ./ProCon 400 5
註:該博文為<<unix網路編程 --卷二>>讀書筆記