进程同步的经典问题1——读者写者问题(写者优先与公平竞争)

来源:互联网 发布:王自如 罗永浩 知乎 编辑:程序博客网 时间:2024/04/28 23:45

http://blog.csdn.net/cz_hyf/article/details/4443551

读者-写者问题 写者优先与公平竞争

多进程对共享资源互斥访问及进程同步的经典问题
 
设有一文件F,多个并发读进程和写进程都要访问,要求:
(1)读写互斥
(2)写写互斥
(3)允许多个读进程同时访问
采用记录型信号量机制解决
 
较常见的写法:

semaphore fmutex=1, rdcntmutex=1;
//fmutex --> access to file; rdcntmutex --> access to readcount
int readcount = 0;
void reader(){
    while(1){
        wait(rdcntmutex);
        if(0 == readcount)wait(fmutex);
        readcount = readcount + 1;
        signal(rdcntmutex);
        //Do read operation ...
        wait(rdcntmutex);
        readcount = readcount - 1;
        if(0 == readcount)signal(fmutex);
        signal(rdcntmutex);
    }
}
void writer(){
    while(1){
        wait(fmutex);
        //Do write operation ...
        signal(fmutex);
    }
}

读进程只要看到有其他读进程正在访问文件,就可以继续作读访问;写进程必须等待所有读进程都不访问时才能写文件,即使写进程可能比一些读进程更早提出申请。所以以上解法实际是 读者优先 的解法。如果在读访问非常频繁的场合,有可能造成写进程一直无法访问文件的局面....
 
为了解决以上问题,需要提高写进程的优先级。这里另增加一个排队信号量:queue。读写进程访问文件前都要在此信号量上排队,通过区别对待读写进程便可达到提高写进程优先级的目的。另外再增加一个 writecount 以记录提出写访问申请和正在写的进程总数:

semaphore fmutex=1, rdcntmutex=1, wtcntmutex=1, queue=1;
//fmutex --> access to file; rdcntmutex --> access to readcount
//wtcntmutex --> access to writecount
int readcount = 0, writecount = 0;
void reader(){
    while(1){
        wait(queue);
        wait(rdcntmutex);
        if(0 == readcount)wait(fmutex);
        readcount = readcount + 1;
        signal(rdcntmutex);
        signal(queue);
        //Do read operation ...
        wait(rdcntmutex);
        readcount = readcount - 1;
        if(0 == readcount)signal(fmutex);
        signal(rdcntmutex);
    }
}
void writer(){
    while(1){
        wait(wtcntmutex);
        if(0 == writecount)wait(queue);
        writecount = writecount + 1;
        signal(wtcntmutex);
        wait(fmutex);
        //Do write operation ...
        signal(fmutex);
        wait(wtcntmutex);
        writecount = writecount - 1;
        if(0 == writecount)signal(queue);
        signal(wtcntmutex);
    }
}

每个读进程最开始都要申请一下 queue 信号量,之后在真正做读操作前即让出(使得写进程可以随时申请到 queue)。而只有第一个写进程需要申请 queue,之后就一直占着不放了,直到所有写进程都完成后才让出。等于只要有写进程提出申请就禁止读进程排队,变相提高了写进程的优先级。
 
通过类似思想即可实现读写进程的公平竞争:

semaphore fmutex=1, rdcntmutex=1, queue=1;
//fmutex --> access to file; rdcntmutex --> access to readcount
int readcount = 0;
void reader(){
    while(1){
        wait(queue);
        wait(rdcntmutex);
        if(0 == readcount)wait(fmutex);
        readcount = readcount + 1;
        signal(rdcntmutex);
        signal(queue);
        //Do read operation ...
        wait(rdcntmutex);
        readcount = readcount - 1;
        if(0 == readcount)signal(fmutex);
        signal(rdcntmutex);
    }
}
void writer(){
    while(1){
        wait(queue);
        wait(fmutex);
        signal(queue);
        //Do write operation ...
        signal(fmutex);
    }
}

读进程没变,写进程变成在每次写操作前都要等待 queue 信号量。
 
课本上一般只会写第一种解法吧。看了后两种方法即可发现,在第一个解法中,fmutex 信号量实际是双重身份,首先实现对文件的互斥访问,其次起到了和后面排队信号量 queue 相同的作用,只不过在那种排序下只能是读者优先。如果直接看过后两种解法,应该会有更清楚的理解吧。
*******************************************************************************************************************

写了两个小程序验证

复制代码
1 /*
 2  *   读者写者问题,读者优先
 3  *   <<操作系统-内核与设计原理>> p183,p184
 4  *   有读者在读那么后来的读者就可以继续读,而已经在等待的写者继续等待,
 5  *   直到某个时刻没有任何读者。
 6  *   读者之间不互斥,写者之间互斥,只能一个写,可以多个读,
 7  *   读者写者之间互斥,有写者写则不能有读者读
 8  *   所以只需要当前第一个读者和写者竞争,竞争成功则后面的读者因为
 9  *   已经有读者在读,可以直接读。
10  */
11 #include  <stdio.h>
12 #include  <pthread.h>
13 #include  <ctype.h>
14 #include <semaphore.h>
15 
16 static sem_t sem_x;  //保证readcount被正确更新
17 static sem_t sem_wsem; //保证读写,写写互斥
18 static int readcount = 0;
19 void *write(void *a) 
20 {
21     sem_wait(&sem_wsem);
22     
23     //writting
24     printf("Writer is writting no reader allowed\n");
25     sleep(2);
26     printf("Finished writting\n");
27     //end of writting
28 
29     sem_post(&sem_wsem);
30 }
31 
32 void *read(void *a) 
33 {
34     int *= (int *)a;
35     int tid = *+ 1;
36     int i;
37     for (i = 0; i < 2; i++) {
38         sem_wait(&sem_x);
39         readcount++;
40         printf("Reader count is %d\n", readcount);
41         if (readcount == 1)
42             sem_wait(&sem_wsem);
43         sem_post(&sem_x);
44 
45         //reading
46         printf("Reader %d is reading\n", tid);
47         sleep(2);
48         printf("Finshed reading\n");
49 
50         sem_wait(&sem_x);
51         readcount--;
52         if (readcount == 0)
53             sem_post(&sem_wsem);
54         sem_post(&sem_x);
55     }
56 }
57 
58 int main(int argc, char *argv[])
59 {
60     pthread_t reader_tid[20];
61     pthread_t writer_tid[10];
62     
63     //init semaphore
64     if(sem_init(&sem_x,01== -1 ||
65        sem_init(&sem_wsem, 01== -1) {
66         printf("Failed to init semaphore!\n");
67         exit(1);
68     }
69 
70     int i;
71     for (i = 0; i < 10; i++)
72         pthread_create(&reader_tid[i], NULL, read,(void *&i);
73     for (i = 0; i < 5; i++)
74         pthread_create(&writer_tid[i], NULL, write, (void *&i);
75     for (i = 10; i < 20; i++)
76         pthread_create(&reader_tid[i], NULL, read,(void *&i);
77     for (i = 5; i < 10; i++)
78         pthread_create(&writer_tid[i], NULL, write,(void *&i);
79 
80     for (i = 0; i < 20; i++)
81         pthread_join(reader_tid[i], NULL);
82     for (i = 0; i < 10; i++)
83         pthread_join(writer_tid[i], NULL);
84 
85     printf("Final read count is %d\n", readcount);
86     return 0;
87 }
复制代码
//test
Reader count is 1
Reader 1 is reading
Reader count is 2
Reader 2 is reading
Reader count is 3
Reader 3 is reading
Reader count is 4
Reader 4 is reading
Reader count is 5
Reader 5 is reading
Reader count is 6
Reader 6 is reading
Reader count is 7
Reader 7 is reading
Reader count is 8
Reader 8 is reading
Reader count is 9
Reader 9 is reading
Reader count is 10
Reader 10 is reading
Reader count is 11
Reader 11 is reading
Reader count is 12
Reader 12 is reading
Reader count is 13
Reader 13 is reading
Reader count is 14
Reader 14 is reading
Reader count is 15
Reader 15 is reading
Reader count is 16
Reader 16 is reading
Reader count is 17
Reader 17 is reading
Reader count is 18
Reader 18 is reading
Reader count is 19
Reader 19 is reading
Reader count is 20
Reader 20 is reading
Finshed reading
Reader count is 20
Reader 1 is reading
Finshed reading
Reader count is 20
Reader 2 is reading
Finshed reading
Reader count is 20
Reader 3 is reading
Finshed reading
Reader count is 20
Reader 4 is reading
Finshed reading
Reader count is 20
Reader 5 is reading
Finshed reading
Reader count is 20
Reader 6 is reading
Finshed reading
Reader count is 20
Reader 7 is reading
Finshed reading
Reader count is 20
Reader 8 is reading
Finshed reading
Reader count is 20
Reader 9 is reading
Finshed reading
Reader count is 20
Reader 10 is reading
Finshed reading
Reader count is 20
Reader 11 is reading
Finshed reading
Reader count is 20
Reader 12 is reading
Finshed reading
Reader count is 20
Reader 13 is reading
Finshed reading
Reader count is 20
Reader 14 is reading
Finshed reading
Reader count is 20
Reader 15 is reading
Finshed reading
Reader count is 20
Reader 16 is reading
Finshed reading
Reader count is 20
Reader 17 is reading
Finshed reading
Reader count is 20
Reader 18 is reading
Finshed reading
Reader count is 20
Reader 19 is reading
Finshed reading
Reader count is 20
Reader 20 is reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Writer is writting no reader allowed
Finished writting
Final read count is 0



复制代码
  1 /*
  2  *   读者写者问题,写者优先
  3  *   <<操作系统-内核与设计原理>> p185,p16
  4  *  当写者出现后,后来的读者会被阻塞,直到没有写者。
  5  *  
  6  *  第一个读者和写者竞争,如果失败了,证明有写者
  7  *  后来的读者将在另一个信号量上排队。
  8  *  
  9  *  在rsem不允许建立读者长队列,否则当同时有很多读进程
 10  *  和第一个写者出现,可能写者会在rsem的竞争中排在后面
 11  *  不能跳过前面的读者。保证了第一写者writecount=1的优先地位,
 12  *  但是实验一般测不出来,有没有sem_z一样的,因为,读者在rsem
 13  *  上排队的时间太短了,比如writecount == 0了 singnal rsem
 14  *  然后很快的所有排队的读者就都获得了读的权利,队列变空。除非实验能够
 15  *  在这个时候出先一个写者,这样有sem_z则写者至多让前面的一个读者读,
 16  *  就取得了写权利,
 17  *  而没有的话,rsem对了写者前面的都会去读,意义不大。
 18  *  if (writecount == 1)    
 19         sem_wait(&sem_rsem);
 20     确保了后续写者相对读者的优先地位.这个是主要的写者优势。
 21  */
 22 #include  <stdio.h>
 23 #include  <pthread.h>
 24 #include  <ctype.h>
 25 #include <semaphore.h>
 26 
 27 static sem_t sem_x;     //保证readcount被正确更新
 28 static sem_t sem_y;     //保证writercount被正确更新
 29 static sem_t sem_z;     //竞争rsem失败后,后续读者在此排队
 30 static sem_t sem_wsem;  //保证读写,写写互斥
 31 static sem_t sem_rsem;  //当一个写者出现,用于禁止所有的读进程
 32 static int readcount = 0;
 33 static int writecount = 0;
 34 void *write(void *a) 
 35 {
 36     int *= (int *)a;
 37     int tid = *+ 1;
 38     sem_wait(&sem_y);
 39     writecount++;
 40     printf("Writter count is %d\n", writecount);
 41     if (writecount == 1)    //写者在rsem的竞争中优先
 42         sem_wait(&sem_rsem);
 43     sem_post(&sem_y);
 44     
 45     sem_wait(&sem_wsem);
 46 
 47     //writting
 48     printf("Writer %d is writting no reader allowed\n", tid);
 49     sleep(2);
 50     printf("Finished writting\n");
 51     //end of writting
 52 
 53     sem_post(&sem_wsem);
 54 
 55     sem_wait(&sem_y);
 56     writecount--;
 57     if (writecount == 0)
 58         sem_post(&sem_rsem);
 59     sem_post(&sem_y);
 60 }
 61 
 62 void *read(void *a) 
 63 {
 64     int *= (int *)a;
 65     int tid = *+ 1;
 66     int i;
 67     for (i = 0; i < 2; i++) {
 68         sem_wait(&sem_z);
 69         sem_wait(&sem_rsem);
 70         sem_wait(&sem_x);
 71         readcount++;
 72         printf("Reader count is %d\n", readcount);
 73         if (readcount == 1)
 74             sem_wait(&sem_wsem);
 75         sem_post(&sem_x);
 76         sem_post(&sem_rsem);
 77         sem_post(&sem_z);
 78 
 79         //reading
 80         printf("Reader %d is reading\n", tid);
 81         sleep(2);
 82         printf("Finshed reading\n");
 83         //end of reading
 84 
 85         sem_wait(&sem_x);
 86         readcount--;
 87         if (readcount == 0)
 88             sem_post(&sem_wsem);
 89         sem_post(&sem_x);
 90     }
 91 }
 92 
 93 int main(int argc, char *argv[])
 94 {
 95     pthread_t reader_tid[20];
 96     pthread_t writer_tid[10];
 97     
 98     //init semaphore
 99     if(sem_init(&sem_x,01== -1 ||
100        sem_init(&sem_y,01== -1 ||
101        sem_init(&sem_z,01== -1 ||
102        sem_init(&sem_wsem, 01== -1 ||
103        sem_init(&sem_rsem, 01== -1) {
104         printf("Failed to init semaphore!\n");
105         exit(1);
106     }
107 
108     int i;
109     for (i = 0; i < 10; i++)
110         pthread_create(&reader_tid[i], NULL, read,(void *&i);
111     for (i = 0; i < 5; i++)
112         pthread_create(&writer_tid[i], NULL, write, (void *&i);
113     for (i = 10; i < 20; i++)
114         pthread_create(&reader_tid[i], NULL, read,(void *&i);
115     for (i = 5; i < 10; i++)
116         pthread_create(&writer_tid[i], NULL, write,(void *&i);
117 
118     for (i = 0; i < 20; i++)
119         pthread_join(reader_tid[i], NULL);
120     for (i = 0; i < 10; i++)
121         pthread_join(writer_tid[i], NULL);
122 
123     return 0;
124 }
复制代码
//test
Reader count is 1
Reader 1 is reading
Reader count is 2
Reader 2 is reading
Reader count is 3
Reader 3 is reading
Reader count is 4
Reader 4 is reading
Reader count is 5
Reader 5 is reading
Reader count is 6
Reader 6 is reading
Reader count is 7
Reader 7 is reading
Reader count is 8
Reader 8 is reading
Reader count is 9
Reader 9 is reading
Reader count is 10
Reader 10 is reading
Writter count is 1
Writter count is 2
Writter count is 3
Writter count is 4
Writter count is 5
Writter count is 6
Writter count is 7
Writter count is 8
Writter count is 9
Writter count is 10
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Writer 1 is writting no reader allowed
Finished writting
Writer 2 is writting no reader allowed
Finished writting
Writer 3 is writting no reader allowed
Finished writting
Writer 4 is writting no reader allowed
Finished writting
Writer 5 is writting no reader allowed
Finished writting
Writer 6 is writting no reader allowed
Finished writting
Writer 7 is writting no reader allowed
Finished writting
Writer 8 is writting no reader allowed
Finished writting
Writer 9 is writting no reader allowed
Finished writting
Writer 10 is writting no reader allowed
Finished writting
Reader count is 1
Reader 11 is reading
Reader count is 2
Reader 12 is reading
Reader count is 3
Reader 13 is reading
Reader count is 4
Reader 14 is reading
Reader count is 5
Reader 15 is reading
Reader count is 6
Reader 16 is reading
Reader count is 7
Reader 17 is reading
Reader count is 8
Reader 18 is reading
Reader count is 9
Reader 19 is reading
Reader count is 10
Reader 20 is reading
Reader count is 11
Reader 1 is reading
Reader count is 12
Reader 2 is reading
Reader count is 13
Reader 3 is reading
Reader count is 14
Reader 4 is reading
Reader count is 15
Reader 5 is reading
Reader count is 16
Reader 6 is reading
Reader count is 17
Reader 7 is reading
Reader count is 18
Reader 8 is reading
Reader count is 19
Reader 9 is reading
Reader count is 20
Reader 10 is reading
Finshed reading
Reader count is 20
Reader 11 is reading
Finshed reading
Reader count is 20
Reader 12 is reading
Finshed reading
Reader count is 20
Reader 13 is reading
Finshed reading
Reader count is 20
Reader 14 is reading
Finshed reading
Reader count is 20
Reader 15 is reading
Finshed reading
Reader count is 20
Reader 16 is reading
Finshed reading
Reader count is 20
Reader 17 is reading
Finshed reading
Reader count is 20
Reader 18 is reading
Finshed reading
Reader count is 20
Reader 19 is reading
Finshed reading
Reader count is 20
Reader 20 is reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading
Finshed reading

0 0
原创粉丝点击