弱读者优先
在这一版本的实现中需要在已经有读者在读的情况下优先响应正在等待的读者而不是写者,代码如下:
int rc = 0;
sem_t mutex, w;
void reader()
{
while(true) {
P(&mutex);
rc++;
if(rc == 1)
P(&w);
V(&mutex);
...read...
P(&mutex);
rc--;
if(rc == 0)
V(&w);
V(&mutex);
}
}
void writer()
{
while(true)
{
P(&w);
...write...
V(&w);
}
}
在这个方案中只有第一个读者需要和写者一起排队,而其他读者与第一个读者有相同的优先级,相当于站在第一个读者的旁边,只要第一个读者被允许读那么和他站在一起的读者也就能读,图示如下:
强读者优先
上面的弱读者优先实现在写者出关键区的时候可能会调度写者执行,即使有等待的读者。强读者优先保证无论是读者还是写者离开关键区,只要有读者正在等待就会选择读者执行。
int rc = 0;
sem_t mutex, w, wq;
void reader()
{
while(1) {
P(&mutex);
rc++;
if(rc == 1)
P(&w);
V(&mutex);
...read...
P(&mutex);
rc--;
if(rc == 0)
V(&w);
V(&mutex);
}
}
void writer()
{
while(1)
{
P(&wq);
P(&w);
...write...
V(&w);
V(&wq);
}
}
相较于弱读者优先,上面的代码中写者不是在w
队列中等待而是在wq
中等待,当有一个写者离开临界区时总是先选择w
队列中一个正在等待的任务,而不可能有超过一个写者在w
队列中,因此内核会选择读者执行。故上面的代码实现了强读者优先。
最多有N个读者情况下读者和写者有相同优先级
最多有N个读者,等待中的读者和写者被赋予对资源访问的同等机会。机会相等意味着读者和写者要在同一个队列中等待,可以有多个读者同时读的代码如下代码如下:
int cap = N;
sem_t mutex, w;
void reader()
{
int in = 0;
P(&mutex);
cap--;
if (cap < 0) {
in = 1;
V(&mutex);
P(&w);
}
else
V(&mutex);
/* read... */
P(&mutex);
cap++;
if (in == 1) {
in = 0;
V(&w);
}
V(&mutex);
}
void writer()
{
P(&mutex);
cap -= N;
P(&w);
V(&mutex);
/* write... */
P(&mutex);
cap += N;
V(&mutex);
}
也可以只允许同时有一个写者或读者,写者和读者都在一个队列中等待。
sem_t mutex;
sem_t readercnt;
void reader() {
P(&readercnt);
P(&mutex);
/* read... */
V(&mutex);
V(&readercnt);
}
}
void writer() {
P(&mutex);
/* write... */
V(&mutex);
}
写者优先
在一个等待的写者之后到来的读者都处于等待状态(重复执行循环),只有当前不存在写者才会允许读。
sem_t mutex, r, w, mutex2;
int wc = 0, rc = 0;
void reader()
{
while (1) {
// writer first
P(&mutex);
if (writecnt > 0) {
V(&mutex);
continue;
}
else
V(&mutex);
P(&w);
/* Critical section */
readtimes++;
/* Critical section */
V(&w);
break;
}
}
void write()
{
P(&mutex);
wc++;
V(&mutex);
P(&w);
/* write...*/
V(&w);
P(&mutex);
wc--;
V(&mutex);
}