[unix系统编程]读者-写者问题

来源:互联网 发布:苹果手机视频软件 编辑:程序博客网 时间:2024/06/10 07:40

读者一写者问题是一个用信号量实现的经典进程同步问题。在系统中,一个数据集( 如文件或记录) 被几个并发进程共享,这些线程分两类,一部分只要求进行读操作,称之为“读者”;另一类要求写或修改操作,我们称之为“写者“。

一般而言,对一个数据集,为了保证数据的完整性、正确性,允许多个读者进程同时访问,但是不允许一个写者进程同其它任何一个进程(读者或者写者)同时访问,而这类问题就称之为”读者-写者“问题。

 

读者优先的算法在操作系统相关的书籍中都有介绍,这是一种最简单的解决办法:当没有写进程正在访问共享数据集时,读进程可以进入访问,否则必须等待。而读者优先的算法存在“饿死写者”线程的问题:只要有读者不断到来,写者就要持久地等待,直到 所有的读者都读完且没有新的读者到来时写者才能写数据集。而在很多情况下我们需要避免”饿死写者“,故而采用写者优先算法:

 

在写者优先算法中,我们要实现的目标是:

1.要让读者与写者之间、以及写者与写者之问要互斥地访同数据集;

2.在无写进程到来时各读者可同时访问数据集;

3.在读者和写者都等待时访问时写者优先.


读者写者的伪代码:


程序一,上面伪代码的具体实现,写者可能饿死:

#include <pthread.h>#include <signal.h>#include "apue.h"#define N5 //No. of readerpthread_mutex_t rd = PTHREAD_MUTEX_INITIALIZER; // it's mean reader can readingpthread_mutex_t wr = PTHREAD_MUTEX_INITIALIZER; //it's mean writer can writingint readCount = 0;void* reader(void *arg){int n = 6;int id = (int)arg;while (n--) {sleep( rand() % 3);pthread_mutex_lock(&rd);readCount++;if( readCount == 1){pthread_mutex_lock(&wr);}pthread_mutex_unlock(&rd);printf("reader %d is reading\n", id);sleep( rand() % 3);pthread_mutex_lock(&rd);readCount--;if (readCount == 0) {pthread_mutex_unlock(&wr);}pthread_mutex_unlock(&rd);printf("reader %d is leaving\n", id);}printf("----reader %d has done----\n", (int)arg);}void* writer(void *arg){int n = 6;while (n--) {sleep( rand() % 3);pthread_mutex_lock(&wr);printf("\twriter is writing\n");sleep( rand() % 3);pthread_mutex_unlock(&wr);printf("\twriter is leaving\n");}printf("----writer has done----\n");}int main(int argc, const char *argv[]){int err;pthread_t tid[N], writerTid;int i;for (i = 0; i < N; i++) {err = pthread_create(&tid[i], NULL, reader, (void *)(i+1));if (err != 0) {err_quit("can't create process for reader");}}err = pthread_create(&writerTid, NULL, writer, (void *)NULL);if (err != 0) {err_quit("can't create process for writer");}pause();return 0;}


程序二,与程序一基本一样,只是增加了一个互斥量,用于写者优先,当有写者来的时候,就不在允许读者去读取数据,等待正在读数据的读者完成以后开始写数据,以此实现写者优先,从程序的运行结果可以看出,没有采取这步措施以前,读者执行能够得到执行,而写者需要等待很久才有机会执行。采取这步措施以后,写者比如何读者都有更高的优先权,可以优先执行。

#include <pthread.h>#include <signal.h>#include "apue.h"#define N5 //No. of readerpthread_mutex_t rd = PTHREAD_MUTEX_INITIALIZER; // it's mean reader can readingpthread_mutex_t wr = PTHREAD_MUTEX_INITIALIZER; //it's mean writer can writingpthread_mutex_t priority = PTHREAD_MUTEX_INITIALIZER; //it's mean writer can writingint readCount = 0;void* reader(void *arg){int n = 6;int id = (int)arg;while (n--) {sleep( rand() % 3);pthread_mutex_lock(&priority);pthread_mutex_lock(&rd);readCount++;if( readCount == 1){pthread_mutex_lock(&wr);}pthread_mutex_unlock(&rd);pthread_mutex_unlock(&priority);printf("reader %d is reading\n", id);sleep( rand() % 3);pthread_mutex_lock(&rd);readCount--;if (readCount == 0) {pthread_mutex_unlock(&wr);}pthread_mutex_unlock(&rd);printf("reader %d is leaving\n", id);}printf("----reader %d has done----\n", (int)arg);}void* writer(void *arg){int n = 6;while (n--) {sleep( rand() % 3);pthread_mutex_lock(&priority);pthread_mutex_lock(&wr);printf("\twriter is writing\n");sleep( rand() % 3);pthread_mutex_unlock(&wr);pthread_mutex_unlock(&priority);printf("\twriter is leaving\n");}printf("----writer has done----\n");}int main(int argc, const char *argv[]){int err;pthread_t tid[N], writerTid;int i;for (i = 0; i < N; i++) {err = pthread_create(&tid[i], NULL, reader, (void *)(i+1));if (err != 0) {err_quit("can't create process for reader");}}err = pthread_create(&writerTid, NULL, writer, (void *)NULL);if (err != 0) {err_quit("can't create process for writer");}pause();return 0;}


程序三,用unix线程调度中的Reader-Writer Locks锁,实现同样的功能,但是代码简洁了很多。(有一点让我困惑的是,unix环境高级编程中有这么一句话:Although implementations vary, reader-writer locks usually block additional readers if a lock is already held in read mode and a thread is blocked trying to acquire the lock in write mode. This prevents a constant stream of readers from starving waiting writers. 这句话的意思应该是说具体实现是写者优先,但是从运行结果来看好像是读者优先,当然了,书上明确说了,取决于具体的实现,但是我分别在两台电脑上(Ubuntu 和 纯 unix 操作系统)运行了一下,结果似乎都是读者优先,而google了一下也还没有得到结果,如果您看到了,并且知道,请告诉我,ps:要有证据噢)。

#include <apue.h>#include <pthread.h>#include <signal.h>#include "apue.h"#define N5 //No. of readerpthread_rwlock_t lock; //it's mean writer can writingint readCount = 0;void* reader(void *arg){int n = 6;int id = (int)arg;while (n--) {sleep( rand() % 3);pthread_rwlock_rdlock(&lock);printf("reader %d is reading\n", id);sleep( rand() % 3);pthread_rwlock_unlock(&lock);printf("reader %d is leaving\n", id);}printf("----reader %d has done----\n", (int)arg);}void* writer(void *arg){int n = 6;while (n--) {sleep( rand() % 3);pthread_rwlock_wrlock(&lock);printf("\twriter is writing\n");sleep( rand() % 3);pthread_rwlock_unlock(&lock);printf("\twriter is leaving\n");}printf("----writer has done----\n");}int main(int argc, const char *argv[]){int err;pthread_t tid[N], writerTid;int i;pthread_rwlock_init(&lock, NULL);for (i = 0; i < N; i++) {err = pthread_create(&tid[i], NULL, reader, (void *)(i+1));if (err != 0) {err_quit("can't create process for reader");}}err = pthread_create(&writerTid, NULL, writer, (void *)NULL);if (err != 0) {err_quit("can't create process for writer");}pause();pthread_rwlock_destroy(&lock);return 0;}
运行方法:

需要unix环境高级编程的apue.h头文件,和错误处理文件

gcc prog.c apue.h error.c -l pthread

./a.out

原创粉丝点击