读者写者问题

问题描述:有读者和写者两组并发进程,共享一个文件。

分析:当多个读进程共同访问时不会出现问题(读进程与消费者不一样,读进程不会讲数据清空,并不会改变数据),但写进程和其他进程(读进程或者写进程)同时访问时会出现问题,比如一边写一遍读,我这边刚写完,你又来写;因此有如下要求

1 允许多个读者共同访问共享文件的数据

2 只允许一个写者往文件里写

3 任一写者未完成写操作时,不允许任何读者或写者进入

4 写者进入写操作前,应让已有的读者和写者退出

分析:

都是互斥关系:读进程-写进程,写进程-写进程,读进程-读进程必须要互斥

因为写进程要和任一进程都互斥,因此设置一个rw的互斥信号量,在写进程前后分别用P,V操作,因为读进程与写进程也互斥,因此我也得在读进程前后也分别用P,V操作,那么这个时候如果我已经有一个读进程在读了,我另一个读进程也想读,就会被P操作这一步阻塞,这违背了读进程-读进程不互斥。接下来就是读者写者的核心问题了—用count来控制,我们可以把P,V操作分别理解为加锁和解锁,那我第二个读进程再想进就不应该再加锁了,应该跳过这一步直接往下去读,因此这个时候的解决方法就是用count去判断是第几个读进程想进去,然后跳过加锁过程。

实现自己和自己不互斥,自己和别人互斥,考虑用count计数器

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
semaphore rw = 1;
int count = 0;
writer(){
while(1){
P(rw);
写文件;
V(rw);
}
}
reader(){
while(1){
if(count==0){
P(rw);
}
count++;
读文件;
count--;
if(count==0){
V(rw);
// 如果是最后一个读进程,需解锁
}
}
}

但是如果第一个读进程进行完P操作之后还没进入共享文件就切换到了第二个读进程,这时count仍为0,那第二个读进程也要进行P操作,但这时他就要被阻塞了,因此上面的方法还是不行,那问题出在哪,显然是因为检查和改变count没有一气呵成,那解决一气呵成问题应该很自然的想到用互斥的方法,因此我们应该再加一个互斥信号量mutex,让进程在每次进行检查和改变count值得时候都P,V操作一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
reader(){
while(1){
P(mutex)
if(count==0){
P(rw);
}
count++;
V(mutex)
读文件;
P(mutex);
count--;
if(count==0){
V(rw);
}
V(mutex);
}

这个时候第一个读者在进行P(rw)和count++是一起呵成的,他不完成这两步然后V(mutex),第二个读进程只能一直被阻塞,等他完成了,第二个读进程进来因为此时count已经是1了,因此第二个读进程直接count++,接着往下走就行了。至此,关于互斥的操作就都完成了

但是如果有很多读进程都在读,那写进程就要一直等,这样就造成了饥饿,也就是读进程优先,那解决这个问题我们可以再加一个互斥信号量w

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
semaphore rw = 1;
semaphore mutex = 1;
semaphore w = 1;
writer(){
while(1){
P(w)
P(rw);
写文件;
V(rw);
V(w);
}
}
reader(){
while(1){
P(w)
P(mutex)
if(count==0){
P(rw);
}
count++;
V(mutex)
V(w)
读文件;
P(mutex);
count--;
if(count==0){
V(rw);
}
V(mutex);
}

我们来验证下可不可以

读者1->读者2:读者以进来后w=0,mutex=0,rw=0,count=1;在没有进行V操作之前,读者2被阻塞,进行V操作之后读进程可以跳过P(rw)正常向下,也就是即实现了一气呵成,又满足读者进程和读者进程不互斥

写者1->写者2:这个与上面的类似,很好证明成立

写者1->读者1:当写者没写完,w永远是0,读者会被阻塞在P(w),反之亦然,因而读者和写者之间互斥成立

读者1->写者1->读者2: 在读者1一直走一直走到V(w)这一步后,之前被阻塞的写者1才能被唤醒,只要写者没写完进行V(w),读者2就一直被阻塞

写者1->读者1->写者2: 在写者V(w)后,第一个唤醒的是读者1,读者1V(rw)之后,写者2被唤醒

根据上面的验证我们发现这样完全可行,不会读进程一进来就畅行无阻,阻塞写进程,不会造成谁优先谁饥饿,是一种公平的状态

-------------本文结束感谢您的阅读-------------