欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

操作系统学习笔记——读者写者问题

程序员文章站 2022-07-04 23:34:44
...

动机:共享数据的访问

两种类型使用者:读者,不需要修改数据;写者,读取和修改数据

问题的约束:

        允许同一时间有多个读者,但在任何时候只有一个写者;当没有写者时,读者才能访问数据;当没有读者和写者时,写者才能访问数据;在任何时候只能有一个线程可以操作共享变量。

 

多个并发进程的数据集共享:读者-只读数据集;他们不执行任何更新。写者 - 可以读取和写入

共享数据: 数据集data;信号量CountMutex,保证Rcount的互斥,初始化为1;信号量WriteMutex,对写者的互斥保护,初始化为1;整数Rcount代表多少个读者,初始化为0

 

信号量实现,读者优先

写者

sem_wait(WriteMutex);

write;

sem_post(WriteMutex);





读者
sem_wait(CountMutex); 对Rcount做互斥保护
if(Rcount == 0)  
    sem_wait(WriteMutex);  //将read包起来
++Rcount;
sem_post(CountMutex); 所以这一句和上面的那句包起来中间的部分

read;

sem_wait(CountMutex); 对Rcount做互斥保护
--Rcount;
if(Rcount==0)
    sem_post(WriteMutex);  //将read包起来
sem_post(CountMutex); 所以这一句和上面的那句包起来中间的部分

 

用管程实现写者优先

伪码:

Database::Read(){
    Wait until no writers;
    read database;
    check our - wake up waiting writers;
}

Database::Write(){
    Wait until no readers/writes;
    write database;
    check out - wake up waiting readers/writers;
}

管程的状态变量:

AR = 0;  //活动的读者
AW = 0;  //活动的写者
WR = 0;  //等待的读者
WW = 0;  //等待的写者
Condition okToRead;//两个条件变量
Condition okToWrite;
Lock lock;  //互斥

读者的实现:

Public Database::Read(){
    //wait until no writers;
    StartRead();
    read database;
    //check out - wake up waiting writers;
    DoneRead();
}

Private Database::StartRead(){
    lock.Acquire();//确保只有一个函数进入管程
    while( (AW+WW)>0 ){//存在写者
        WR++;
        okToRead.wait(&lock);//去等待,释放锁
        WR--;
    }   
    AR++;//读者增加一个
    lock.Release();
}

Private Database::DoneRead(){
    lock.Acquire();
    AR--;    //读完后读者减1
    if( AR==0 && WW>0 ){
        okToWrite.signal();//唤醒写者
    }
    lock.Release();
}

写者:

Public Database::Write(){
    //wait until no readers/writers;
    StartWrite();
    write databse;
    //check out - wake up waiting readers/writers;
    DoneWrite();
}

Private Database::StartWrite(){
    lock.Acquire();
    while( (AW+AR)>0 ){
        WW++;
        okToWrite.wait(&lock);
        WW--;
    }    
    AW++;
    lock.Release();
}

Private Database::DoneWrite(){
    lock.Acquire();
    AW--;        
    if(WW>0){
        okToWrite.signal();//唤醒一个写者
    }
    else if(WR>0){
        okToRead.broadcast();//唤醒所有等待的读者
    }
    lock.Release();
}