讀者優先描述
如果讀者來:
1) 無讀者、寫着,新讀者可以讀;
2) 無寫者等待,但有其他讀者正在讀,新讀者可以讀;
3) 有寫者等待,但有其他讀者正在讀,新讀者可以讀;
4) 有寫者寫,新讀者等
如果寫者來:
1) 無讀者,新寫者可以寫;
2) 有讀者,新寫者等待;
3) 有其他寫者寫或等待,新寫者等待
寫者優先描述
如果讀者來:
1) 無讀者、寫者,新讀者可以讀;
2) 無寫者等待,但有其他讀者正在讀,新讀者可以讀;
3) 有寫者等待,但有其他讀者正在讀,新讀者等;
4) 有寫者寫,新讀者等
如果寫者來:
1) 無讀者,新寫者可以寫;
2) 有讀者,新寫者等待;
3) 有其他寫者或等待,新寫者等待
信號量和互斥鎖的區別
l 互斥量用於線程的互斥,信號量用於線程的同步。
這是互斥量和信號量的根本區別,也就是互斥和同步之間的區別。
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源
l 互斥量值只能為0/1,信號量值可以為非負整數。
也就是說,一個互斥量只能用於一個資源的互斥訪問,它不能實現多個資源的多線程互斥問題。信號量可以實現多個同類資源的多線程互斥和同步。當信號量為單值信號量是,也可以完成一個資源的互斥訪問。
l 互斥量的加鎖和解鎖必須由同一線程分別對應使用,信號量可以由一個線程釋放,另一個線程得到。
讀者優先
使用互斥鎖來確保同一時間只能一個進程寫文件,實現互斥。使用信號量來實現訪問資源的同步。
首先,寫者的代碼應該是這樣一種形式,才能保證同一時刻只有一個寫者修改數據。
考慮到寫者對讀者的影響是:當任何讀者想讀時,寫者都必須被阻塞;並且,讀者阻塞了寫者並停止阻塞之前,后續的任何寫者都會讀者優先於執行。這就如同有一個讀者隊列,當第一個讀者入隊時,寫者完全被阻塞,直到最后一個讀者離開隊列。
據此,可以用 readerCnt來統計讀者的數量,而用信號量 sem_read來互斥各線程對 readerCnt的訪問。

1 /* 2 * 多線程,讀者優先 3 */ 4 5 #include "stdio.h" 6 #include <stdlib.h> 7 #include <pthread.h> 8 #include<semaphore.h> 9 10 11 #define N_WRITER 30 //寫者數目 12 #define N_READER 5 //讀者數目 13 #define W_SLEEP 1 //控制寫頻率 14 #define R_SLEEP 1 //控制讀頻率 15 16 17 pthread_t wid[N_WRITER],rid[N_READER]; 18 pthread_mutex_t mutex_write;//同一時間只能一個人寫文件,互斥 19 sem_t sem_read;//同一時間只能有一個人訪問 readerCnt 20 int data = 0; 21 int readerCnt = 0; 22 void write() 23 { 24 int rd = rand(); 25 printf("write %d\n",rd); 26 data = rd; 27 } 28 void read() 29 { 30 printf("read %d\n",data); 31 } 32 void * writer(void * in) 33 { 34 // while(1) 35 // { 36 pthread_mutex_lock(&mutex_write); 37 printf("寫線程id%d進入數據集\n",pthread_self()); 38 write(); 39 printf("寫線程id%d退出數據集\n",pthread_self()); 40 pthread_mutex_unlock(&mutex_write); 41 sleep(W_SLEEP); 42 // } 43 pthread_exit((void *) 0); 44 } 45 46 void * reader (void * in) 47 { 48 // while(1) 49 // { 50 sem_wait(&sem_read); 51 readerCnt++; 52 if(readerCnt == 1){ 53 pthread_mutex_lock(&mutex_write); 54 } 55 sem_post(&sem_read); 56 printf("讀線程id%d進入數據集\n",pthread_self()); 57 read(); 58 printf("讀線程id%d退出數據集\n",pthread_self()); 59 sem_wait(&sem_read); 60 readerCnt--; 61 if(readerCnt == 0){ 62 pthread_mutex_unlock(&mutex_write); 63 } 64 sem_post(&sem_read); 65 sleep(R_SLEEP); 66 // } 67 pthread_exit((void *) 0); 68 } 69 70 int main() 71 { 72 printf("多線程,讀者優先\n"); 73 pthread_mutex_init(&mutex_write,NULL); 74 sem_init(&sem_read,0,1); 75 int i = 0; 76 for(i = 0; i < N_WRITER; i++) 77 { 78 pthread_create(&wid[i],NULL,writer,NULL); 79 } 80 for(i = 0; i < N_READER; i++) 81 { 82 pthread_create(&rid[i],NULL,reader,NULL); 83 } 84 sleep(1); 85 return 0; 86 }
為了更明顯的看到效果,在main函數中創建了20個寫者和5個讀者。注意編譯時要加上-lpthread指定庫。
寫者優先
寫者優先與讀者優先的不同是:如果讀者來,有寫者等待,但有其他讀者正在讀,新讀者等。
使用兩個互斥鎖mutex_write,mutex_read和兩個信號量sem_read,sem_write來確保訪問資源的互斥和同步。

1 #include "stdio.h" 2 #include <stdlib.h> 3 #include <pthread.h> 4 #include<semaphore.h> 5 6 #define N_WRITER 5 //寫者數目 7 #define N_READER 20 //讀者數目 8 #define W_SLEEP 1 //控制寫頻率 9 #define R_SLEEP 0.5 //控制讀頻率 10 11 12 pthread_t wid[N_WRITER],rid[N_READER]; 13 int data = 0; 14 int readerCnt = 0, writerCnt = 0; 15 pthread_mutex_t sem_read; 16 pthread_mutex_t sem_write; 17 pthread_mutex_t mutex_write; 18 pthread_mutex_t mutex_read; 19 20 void write() 21 { 22 int rd = rand(); 23 printf("write %d\n",rd); 24 data = rd; 25 } 26 void read() 27 { 28 printf("read %d\n",data); 29 } 30 void * writer(void * in) 31 { 32 // while(1) 33 // { 34 sem_wait(&sem_write); 35 {//臨界區,希望修改 writerCnt,獨占 writerCnt 36 writerCnt++; 37 if(writerCnt == 1){ 38 //阻止后續的讀者加入待讀隊列 39 pthread_mutex_lock(&mutex_read); 40 } 41 } 42 sem_post(&sem_write); 43 44 45 pthread_mutex_lock(&mutex_write); 46 {//臨界區,限制只有一個寫者修改數據 47 printf("寫線程id%d進入數據集\n",pthread_self()); 48 write(); 49 printf("寫線程id%d退出數據集\n",pthread_self()); 50 } 51 pthread_mutex_unlock(&mutex_write); 52 53 sem_wait(&sem_write); 54 {//臨界區,希望修改 writerCnt,獨占 writerCnt 55 writerCnt--; 56 if(writerCnt == 0){ 57 //阻止后續的讀者加入待讀隊列 58 pthread_mutex_unlock(&mutex_read); 59 } 60 } 61 sem_post(&sem_write); 62 sleep(W_SLEEP); 63 // } 64 pthread_exit((void *) 0); 65 } 66 67 void * reader (void * in) 68 { 69 // while(1) 70 // { 71 //假如寫者鎖定了mutex_read,那么成千上萬的讀者被鎖在這里 72 pthread_mutex_lock(&mutex_read);//只被一個讀者占有 73 {//臨界區 74 sem_wait(&sem_read);//代碼段 1 75 {//臨界區 76 readerCnt++; 77 if(readerCnt == 1){ 78 pthread_mutex_lock(&mutex_write); 79 } 80 } 81 sem_post(&sem_read); 82 } 83 pthread_mutex_unlock(&mutex_read);//釋放時,寫者將優先獲得mutex_read 84 printf("讀線程id%d進入數據集\n",pthread_self()); 85 read(); 86 printf("讀線程id%d退出數據集\n",pthread_self()); 87 sem_wait(&sem_read);//代碼段2 88 {//臨界區 89 readerCnt--; 90 if(readerCnt == 0){ 91 pthread_mutex_unlock(&mutex_write);//在最后一個並發讀者讀完這里開始禁止寫者執行寫操作 92 } 93 } 94 sem_post(&sem_read); 95 96 sleep(R_SLEEP); 97 // } 98 pthread_exit((void *) 0); 99 } 100 101 int main() 102 { 103 printf("多線程,寫者優先\n"); 104 pthread_mutex_init(&mutex_write,NULL); 105 pthread_mutex_init(&mutex_read,NULL); 106 sem_init(&sem_write,0,1); 107 sem_init(&sem_read,0,1); 108 int i = 0; 109 for(i = 0; i < N_READER; i++) 110 { 111 pthread_create(&rid[i],NULL,reader,NULL); 112 } 113 for(i = 0; i < N_WRITER; i++) 114 { 115 pthread_create(&wid[i],NULL,writer,NULL); 116 } 117 sleep(1); 118 return 0; 119 }