linux多線程編程——讀者優先、寫者優先問題


讀者優先描述

如果讀者來:

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_writemutex_read和兩個信號量sem_readsem_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 }
寫者優先

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM