经典同步问题之读者写者问题
经典同步问题之读者写者问题
读者写者问题中,有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存的一块空间,有一些只读取这个数据区的进程(读者)和一些只往数据区写数据的进程(写者)。此外还需要满足以下条件:
- 任意多个读者可以同时读这个文件
- 一次只能有一个写者可以往文件中写(写者必须互斥)
- 如果一个写者正在操作,禁止任何读进程读文件和其他任何写进程写文件
读者优先算法
一个读者试图进行读操作,如果这时正有其他读者进行读操作,他可以直接开始读,而不需要等待。
读者陆续到来,读者一到就能够开始读操作,而写者进程只能等待所有读者都退出才能够进行写操作
信号量:
- 记录读者数量的整型变量readcount,初值为0,当值大于0时,表明有读者存在,写者不能进行写操作
- 互斥信号量rmutex,初值为1,用户保证多个读者进程对于readcount的互斥访问
- 互斥信号量dmutex,初值为1,用于控制写者进程对于数据区的互斥访问。
semaphore rmutex = 1;
semaphore dmutex = 1;
int readcount = 1;
void reader(){
    while(true){
        P(rmutex);
        if(++readcount == 1) P(dmutex);
        V(rmutex);
        //此处为读操作
        P(rmutex);
        if(--readcount == 0) V(dmutex);
        V(rmutex);
    }
}
void writer(){
    while(true){
        P(dmutex);
        // 此处为写操作
        V(dmutex);
    }
}
Linux中利用pthread库测试代码:
#include <bits/stdc++.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
using namespace std;
//semaphores
sem_t rmutex, dmutex;
int readcount;
struct Data{
    int id;
    int startTime, lastTime;
    Data(){}
    Data(int id, int sT, int lT):id(id), startTime(sT), lastTime(lT){}
};
void *Reader(void *d){
    Data* t = (Data*) d;
    int id = t->id;
    int startTime = t->startTime;
    int lastTime = t->lastTime;
    
    sleep(startTime);
    sem_wait(&rmutex);
    printf("Waiting: %d Reader\n", id);
    readcount ++;
    if(readcount == 1) sem_wait(&dmutex);
    sem_post(&rmutex);
    printf("Reading: %d Reader\n", id);
    sleep(lastTime);
    printf("Finished: %d Reader\n", id);
    sem_wait(&rmutex);
    readcount --;
    if(readcount == 0) sem_post(&dmutex);
    sem_post(&rmutex);
    pthread_exit(0);
}
void *Writer(void *d){
    Data* t = (Data*) d;
    int id = t->id;
    int startTime = t->startTime;
    int lastTime = t->lastTime;
    sleep(startTime);
    printf("Waiting: %d Writer\n", id);
    sem_wait(&dmutex);
    printf("Writing: %d Reader\n", id);
    sleep(lastTime);
    printf("Finished: %d Writer\n", id);
    sem_post(&dmutex);
    pthread_exit(0);
}
int main(){
    pthread_t tid;
    sem_init(&rmutex, 0, 1);
    sem_init(&dmutex, 0, 1);
    readcount = 0;
    int id, startTime, lastTime;    
    string role;
    while(~scanf("%d", &id)){
        cin >> role >> startTime >> lastTime;
        Data *d = new Data(id, startTime, lastTime);
        if(role == "R"){
            printf("Created: %d reader\n", id);
            pthread_create(&tid, NULL, Reader, d);
        } else if(role == "W"){
            printf("Created: %d Writer\n", id);
            pthread_create(&tid, NULL, Writer, d);
        } else puts("Invalid Inputs");
    }
    pthread_exit(0);
}
/*
1 R 1 3
2 W 2 4
3 R 3 5
4 R 4 6
5 W 5 7
*/
编译命令: g++ readfirst.cpp -o readfirst -lpthread
运行:./readfirst

2号写者在2时刻申请写,但实际情况时,直到4号读者读完,2号才开始写
写者优先算法
当写者和读者同时等待时,后续写者到达可以插队到等待的读者之前,只要等待队列中有写者,不管何时到达,都优先于读者被唤醒。
相对于读者优先,新增的信号量:
- 互斥信号量readable,初值为1,用于控制写者到达时可以优先读者进入临界区
- 整型信号量 writecount,初值为0,表示当前写者的数量
- 互斥信号量wmutex,初值为1,用户控制写者互斥访问writecount
semaphore dmutex = 1;
semaphore rmutex = 1;
semaphore wmutex = 1;
semaphore readable = 1;
int readcount = 0, writecount = 0;
void reader(){
    P(readable);    //检查是否有写者,若没有则占用,进行后续操作
    P(rmutex);      //占用rmutex,准备修改readcount
    if(++readcount == 1) P(dmutex); //若是第一个读者,占用数据区
    V(rmutex);      //释放rmutex
    V(readable);    //释放readable
    // 此处为读操作
    P(rmutex);      //占用rmutex
    if(--readcount == 0) V(dmutex); //若为最后一个读者,释放数据区
    V(rmutex);      //释放rmutex
}
void writer(){
    P(wmutex);      //占用wmutex,准备修改writecount
    if(++writecount == 1) P(readable);  //若为第一个写者,则占用readable,阻止后续读者进入
    V(wmutex);      //释放wmutex
    P(dmutex);      //占用dmutex,占用数据区
    // 此处为写操作
    V(dmutex);      //释放rmutex
    P(wmutex);      //占用wmutex,修改writecount
    if(--writecount == 0) P(readable);  //若是最后一个写者,则释放readable允许后续读者进入
    V(wmutex);      //释放wmutex
}
实测代码:
#include <bits/stdc++.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
using namespace std;
sem_t dmutex, rmutex, wmutex, readable;
int readcount, writecount;
struct Data{
    int id;
    int startTime, lastTime;
    Data(int id=0,int startTime=0, int lastTime = 0){
        this->id = id;
        this->startTime = startTime;
        this->lastTime = lastTime;
    }
};
void *Reader(void *d){
    Data* t = (Data*) d;
    int id = t->id;
    int startTime = t->startTime;
    int lastTime = t->lastTime;
    sleep(startTime);
    printf("Wating: %d Reader\n", id);
    sem_wait(&readable);
    sem_wait(&rmutex);
    readcount ++;
    if(readcount == 1) sem_wait(&dmutex);
    sem_post(&rmutex);
    sem_post(&readable);
    printf("Reading: %d Reader\n", id);
    sleep(lastTime);
    printf("Finished: %d Reader\n", id);
    sem_wait(&rmutex);
    if(--readcount == 0) sem_post(&dmutex);
    sem_post(&rmutex);
    
    pthread_exit(0);
}
void *Writer(void *d){
    Data* t = (Data*) d;
    int id = t->id;
    int startTime = t->startTime;
    int lastTime = t->lastTime;
    sleep(startTime);
    printf("Wating: %d Writer\n", id);
    sem_wait(&wmutex);
    if(++writecount == 1) sem_wait(&readable);
    sem_post(&wmutex);
    sem_wait(&dmutex);
    printf("Writing: %d Writer\n", id);
    sleep(lastTime);
    printf("Finished: %d Writer\n", id);
    sem_post(&dmutex);
    sem_wait(&wmutex);
    if(--writecount == 0) sem_post(&readable);
    sem_post(&wmutex);
    pthread_exit(0);
}
int main(){
    freopen("process", "r", stdin);
    pthread_t tid;
    sem_init(&rmutex, 0, 1);
    sem_init(&dmutex, 0, 1);
    sem_init(&wmutex, 0, 1);
    sem_init(&readable, 0, 1);
    readcount = writecount = 0;
    int id, startTime, lastTime;
    string role;
    while(~scanf("%d", &id)){
        cin >> role >> startTime >> lastTime;
        Data *d = new Data(id, startTime, lastTime);
        if(role == "R"){
            printf("Created: %d reader\n", id);
            pthread_create(&tid, NULL, Reader, d);
        } else if(role == "W"){
            printf("Created: %d Writer\n", id);
            pthread_create(&tid, NULL, Writer, d);
        } else puts("Invalid Inputs");
    }
    pthread_exit(0);
}
/*
1 R 1 10
2 R 2 1
3 W 3 10
4 R 14 3
5 W 15 5
*/

3号写者正在写时,4号读者先于5号读者到来,而当3号写者完成写操作时,5号写者率先一步开始写操作
    注:转载请注明出处
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号