互斥量從本質上說是一把鎖,在訪問共享資源前對互斥量進行加鎖,在訪問完成後釋放互斥量上的鎖。對互斥量進行加鎖以後,任何其他試圖再次對互斥量加鎖的線程將會被阻塞直到當前線程釋放該互斥鎖。如果釋放互斥鎖時有多個線程阻塞,所以在該互斥鎖上的阻塞線程都會變成可進行狀態,第一個變成運行狀態的線程可以對互斥量加鎖,其他線程在次被阻塞,等待下次運行狀態。
pthread_mutex_t 就是POSIX對於mutex的實現。
函數名 參數 說明 pthread_mutex_initpthread_mutex_t * mutex,
constpthread_mutex_t *attr 初始化一個互斥量,靜態方式可以直接使用PTHREAD_MUTEX_INITIALIZER進行賦值初始化 pthread_mutex_destroy pthread_mutex_t *mutex 釋放對互斥變量分配的資源。注意pthread_mutex_init有可能malloc了資源 pthread_mutex_lock pthread_mutex_t *mutex 如果互斥量已經上鎖,調用線程阻塞直至互斥量解鎖 pthread_mutex_trylock pthread_mutex_t *mutex 加鎖,如果失敗不阻塞 pthread_mutex_unlock pthread_mutex_t *mutex 解鎖 使用init函數進行初始化:當然該初始化
另外一種用法:
與互斥鎖不同,條件變量是用來等待而不是用來上鎖的。條件變量用來自動阻塞一個線程,直到某特殊情況發生為止。通常條件變量和互斥鎖同時使用。
條件變量使我們可以睡眠等待某種條件出現。條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。
條件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,並釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件變量,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變量可以被用來實現這兩進程間的線程同步。
條件變量的初始化和mutex的初始化差不多,也是有兩種方式:pthread_cond_tmy_condition=PTHREAD_COND_INITIALIZER;
也可以利用函數pthread_cond_init動態初始化。
下面中各個函數的簡介。
函數名 參數 說明 pthread_cond_init pthread_cond_t *cond,
一個簡單使用條件變量進行線程同步的小例子:
/* * pthread_mutex_cond.c * */ #include運行結果:#include #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int i = 0; void *thread1(void *); void *thread2(void *); int main(void) { pthread_t tid1, tid2; if(pthread_create(&tid1, NULL, thread1, NULL)) exit(1); if(pthread_create(&tid2, NULL, thread2, NULL)) exit(1); if(pthread_join(tid1, NULL)) exit(1); printf("thread1 exit\n"); if(pthread_join(tid2, NULL)) exit(1); printf("thread2 exit\n"); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); exit(0); } void *thread1(void *arg) { printf("thread1 start\n"); while(i <= 6) { pthread_mutex_lock(&mutex); printf("thread1: lock %d\n", __LINE__); printf("thread1 i = %d\n", i); if(i%3 == 0) { printf("thread1:signal 1 %d\n", __LINE__); pthread_cond_signal(&cond); printf("thread1:signal 2 %d\n", __LINE__); } pthread_mutex_unlock(&mutex); printf("thread1: unlock %d\n", __LINE__); sleep(1); //sleep 1s,讓線程2得以執行 i++; } pthread_exit((void *)0); } void *thread2(void *arg) { //sleep(1); printf("thread2 start\n"); while(i <= 6) { pthread_mutex_lock(&mutex); printf("thread2: lock %d\n", __LINE__); printf("thread2 i = %d\n", i); if(i%3 != 0) { printf("thread2: wait 1 %d\n", __LINE__); pthread_cond_wait(&cond, &mutex); printf("thread2: wait 2 %d\n", __LINE__); } pthread_mutex_unlock(&mutex); printf("thread2: unlock %d\n", __LINE__); sleep(1); //sleep 1s,讓線程1得以執行 } pthread_exit((void *)0); }
thread2 start
thread2: lock 65
thread2 i = 0
thread2: unlock 75
thread1 start
thread1: lock 42
thread1 i = 0
thread1:signal 1 46
thread1:signal 2 48
thread1: unlock 51
thread2: lock 65
thread2 i = 0
thread2: unlock 75
thread1: lock 42
thread1 i = 1
thread1: unlock 51
thread2: lock 65
thread2 i = 1
thread2: wait 1 69
thread1: lock 42
thread1 i = 2
thread1: unlock 51
thread1: lock 42
thread1 i = 3
thread1:signal 1 46
thread1:signal 2 48
thread1: unlock 51
thread2: wait 2 71
thread2: unlock 75
thread2: lock 65
thread2 i = 3
thread2: unlock 75
thread1: lock 42
thread1 i = 4
thread1: unlock 51
thread2: lock 65
thread2 i = 4
thread2: wait 1 69
thread1: lock 42
thread1 i = 5
thread1: unlock 51
thread1: lock 42
thread1 i = 6
thread1:signal 1 46
thread1:signal 2 48
thread1: unlock 51
thread2: wait 2 71
thread2: unlock 75
thread2: lock 65
thread2 i = 6
thread2: unlock 75
thread1 exit
thread2 exit
/* * producer-consumer.c * */ #include運行結果:#include #include struct msg{ struct msg *next; int num; }; struct msg *head; //共享資源,全局指針初始化為NULL pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *consumer(void *); void *producer(void *); int main(void) { pthread_t tid1,tid2; int res; srand(time(NULL)); res = pthread_create(&tid1,NULL,producer,NULL); if(res != 0) { perror("thread producer create failed\n"); exit(1); } res = pthread_create(&tid2,NULL,consumer,NULL); if(res != 0) { perror("thread consumer create failed\n"); exit(1); } pthread_join(tid1,NULL); if(res != 0) { perror("join thread producer failed\n"); exit(1); } printf("thread producer exit\n"); pthread_join(tid2,NULL); if(res != 0) { perror("join thread consumer failed\n"); exit(1); } printf("thread consumer exit\n"); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&has_product); exit(0); } void *producer(void *arg) { struct msg *mp; int i; printf("producer thread start\n"); for(i=0;i<6;i++) { printf("producer i = %d\n", i); mp = (struct msg *)malloc(sizeof(struct msg)); mp->num = rand()%100 + 1; printf("Produce %d\n", mp->num); pthread_mutex_lock(&mutex); mp->next = head; head = mp; //生產者生產一個結構體串在鏈表的表頭上 pthread_mutex_unlock(&mutex); pthread_cond_signal(&has_product); sleep(1); //讓另一個線程有機會執行 } pthread_exit(NULL); } void *consumer(void *arg) { struct msg *con; int i; printf("consumer thread start\n"); for(i=0;i<6;i++) { printf("consumer i = %d\n", i); pthread_mutex_lock(&mutex); while(head == NULL) { printf("struct msg is null\n"); pthread_cond_wait(&has_product,&mutex); } con = head; //消費者從表頭取走結構體 head = con->next; pthread_mutex_unlock(&mutex); printf("Consume %d\n", con->num); free(con); sleep(1); //讓另一個線程有機會執行 } pthread_exit(NULL); }
consumer thread start
consumer i = 0
struct msg is null
producer thread start
producer i = 0
Produce 52
Consume 52
consumer i = 1
struct msg is null
producer i = 1
Produce 33
Consume 33
consumer i = 2
struct msg is null
producer i = 2
Produce 77
Consume 77
consumer i = 3
struct msg is null
producer i = 3
Produce 86
Consume 86
consumer i = 4
struct msg is null
producer i = 4
Produce 84
Consume 84
consumer i = 5
struct msg is null
producer i = 5
Produce 46
Consume 46
thread producer exit
thread consumer exi
t