操作系统 - C语言实现读者写者问题(写者优先)

同步互斥问题 - 读者写者问题之写者优先

问题要求:
  • 读者-写者问题的读写操作限制(仅读者优先或写者优先):
    • 写-写互斥,即不能有两个写者同时进行写操作。
    • 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。
    • 读-读允许,即可以有一个或多个读者在读。
  • 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
写者优先实现思路:

写者优先与读者优先类似。不同之处在于一旦一个写者到来,它应该尽快对文件进行写操作,如果有一个写者在等待,则新到来的读者不允许进行读操作。为此应当添加一个整型变量write_count,用于记录正在等待的写者的数目,当write_count=0时,才可以释放等待的读者线程队列。


为了对全局变量write_count实现互斥,必须增加一个互斥对象mutex2。


为了实现写者优先,应当添加一个临界区对象read,当有写者在写文件或等待时,读者必须阻塞在read上。同样,有读者读时,写者必须等待。于是,必须有一个互斥对象RW_mutex来实现这个互斥。


有写者在写时,写者必须等待。


读者线程要对全局变量read_count实现操作上的互斥,必须有一个互斥对象命名为mutex1。

实现代码:
代码中信号量解析:
  • 设置五个信号量,分别是RWMutex, mutex1, mutex2, mutex3, wrt,两个全局整型变量writeCount, readCount
  • 信号量mutex1在写者的进入区和退出区中使用,使得每次只有一个写者对其相应进入区或推出区进行操作,主要原因是进入区和退出区存在对变量writeCount的修改,每个写者其进入区中writeCount加1,退出区中writeCount减1。信号量RWMutex则是读者和写者两个之间的互斥信号量,保证每次只读或者只写。写者优先中,写者的操作应该优先于读者,则信号量一直被占用着,直到没有写者的时候才会释放,即当writeCount等于1的时候,申请信号量RWMutex,其余的写者无需再次申请,但是写者是不能同时进行写操作的,则需要设置一个信号量wrt来保证每次只有一个写者进行写操作,当写者的数量writeCount等于0的时候,则证明此时没有没有读者了,释放信号量RWMutex。信号量mutex2防止一次多个读者修改readCount。当readCount为1的时候,为阻止写者进行写操作,申请信号量wrt,则写者就无法进行写操作了。信号量mutex3的主要用处就是避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex3先释放,则一旦有写者,写者可马上获得资源。
实现代码:
/*
* 	写者优先
*/

# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>

//semaphores
sem_t RWMutex, mutex1, mutex2, mutex3, wrt;
int writeCount, readCount;


struct data {
	int id;
	int opTime;
	int lastTime;
};

//读者
void* Reader(void* param) {
	int id = ((struct data*)param)->id;
	int lastTime = ((struct data*)param)->lastTime;
	int opTime = ((struct data*)param)->opTime;

	sleep(opTime);
	printf("Thread %d: waiting to read\n", id);	

	sem_wait(&mutex3);
	sem_wait(&RWMutex);
	sem_wait(&mutex2);
	readCount++;
	if(readCount == 1)
		sem_wait(&wrt);
	sem_post(&mutex2);
	sem_post(&RWMutex);
	sem_post(&mutex3);

	printf("Thread %d: start reading\n", id);
	/* reading is performed */
	sleep(lastTime);
	printf("Thread %d: end reading\n", id);

	sem_wait(&mutex2);
	readCount--;
	if(readCount == 0)
		sem_post(&wrt);
	sem_post(&mutex2);

	pthread_exit(0);
}

//写者
void* Writer(void* param) {
	int id = ((struct data*)param)->id;
	int lastTime = ((struct data*)param)->lastTime;
	int opTime = ((struct data*)param)->opTime;

	sleep(opTime);
	printf("Thread %d: waiting to write\n", id);
	
	sem_wait(&mutex1);
	writeCount++;
	if(writeCount == 1){
		sem_wait(&RWMutex);
	}
	sem_post(&mutex1);
	
	sem_wait(&wrt);
	printf("Thread %d: start writing\n", id);
	/* writing is performed */
	sleep(lastTime);
	printf("Thread %d: end writing\n", id);
	sem_post(&wrt);

	sem_wait(&mutex1);
	writeCount--;
	if(writeCount == 0) {
		sem_post(&RWMutex);
	}
	sem_post(&mutex1);
	
	pthread_exit(0);
}

int main() {
	//pthread
	pthread_t tid; // the thread identifier

	pthread_attr_t attr; //set of thread attributes

	/* get the default attributes */
	pthread_attr_init(&attr);

	//initial the semaphores
    sem_init(&mutex1, 0, 1);
    sem_init(&mutex2, 0, 1);
    sem_init(&mutex3, 0, 1);
    sem_init(&wrt, 0, 1);
    sem_init(&RWMutex, 0, 1);

    readCount = writeCount = 0;

	int id = 0;
	while(scanf("%d", &id) != EOF) {

		char role;		//producer or consumer
		int opTime;		//operating time
		int lastTime;	//run time

		scanf("%c%d%d", &role, &opTime, &lastTime);
		struct data* d = (struct data*)malloc(sizeof(struct data));

		d->id = id;
		d->opTime = opTime;
		d->lastTime = lastTime;

		if(role == 'R') {
			printf("Create the %d thread: Reader\n", id);
			pthread_create(&tid, &attr, Reader, d);

		}
		else if(role == 'W') {
			printf("Create the %d thread: Writer\n", id);
			pthread_create(&tid, &attr, Writer, d);
		}
	}

	sem_destroy(&mutex1);
	sem_destroy(&mutex2);
	sem_destroy(&mutex3);
	sem_destroy(&RWMutex);
	sem_destroy(&wrt);

	return 0;
}
测试

测试数据:

1 R 3 5
2 W 4 5
3 R 5 2
4 R 6 5
5 W 7 3

测试结果:

写者优先测试结果

  • 86
    点赞
  • 488
    收藏
    觉得还不错? 一键收藏
  • 40
    评论
### 回答1: 读者与写者问题是指多个线程同时访问共享资源的情况下可能引发的竞态条件问题,其中包括读者进程和写者进程。 在C语言中,可以使用互斥量和条件变量来实现读者与写者问题的解决方案。 下面是一个简单的读者与写者问题的C代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define READERS_COUNT 5 // 读者数量 #define WRITERS_COUNT 3 // 写者数量 pthread_mutex_t resource_mutex; // 互斥量,用于对共享资源的互斥访问 pthread_mutex_t read_mutex; // 互斥量,用于对读者计数器的互斥访问 pthread_mutex_t write_mutex; // 互斥量,用于对写者计数器的互斥访问 pthread_cond_t read_cond; // 条件变量,用于读者等待 pthread_cond_t write_cond; // 条件变量,用于写者等待 int readers_count = 0; // 读者计数器 int writer_count = 0; // 写者计数器 void *reader(void *arg) { int reader_id = *(int*) arg; while(1) { // 读者等待 pthread_mutex_lock(&resource_mutex); pthread_mutex_lock(&read_mutex); while(writer_count > 0) { pthread_cond_wait(&read_cond, &read_mutex); } readers_count++; pthread_mutex_unlock(&read_mutex); pthread_mutex_unlock(&resource_mutex); // 读取共享资源 printf("Reader %d is reading\n", reader_id); // 读者退出 pthread_mutex_lock(&read_mutex); readers_count--; if(readers_count == 0) { pthread_cond_signal(&write_cond); } pthread_mutex_unlock(&read_mutex); // 等待一段时间后再进行下一轮读取 sleep(rand() % 5); } } void *writer(void *arg) { int writer_id = *(int*) arg; while(1) { // 写者等待 pthread_mutex_lock(&write_mutex); writer_count++; while(readers_count > 0) { pthread_cond_wait(&write_cond, &write_mutex); } pthread_mutex_unlock(&write_mutex); // 写入共享资源 printf("Writer %d is writing\n", writer_id); // 写者退出 pthread_mutex_lock(&write_mutex); writer_count--; pthread_cond_signal(&read_cond); pthread_cond_signal(&write_cond); pthread_mutex_unlock(&write_mutex); // 等待一段时间后再进行下一轮写入 sleep(rand() % 5); } } int main() { pthread_t readers[READERS_COUNT]; pthread_t writers[WRITERS_COUNT]; int reader_ids[READERS_COUNT]; int writer_ids[WRITERS_COUNT]; int i; // 初始化互斥量和条件变量 pthread_mutex_init(&resource_mutex, NULL); pthread_mutex_init(&read_mutex, NULL); pthread_mutex_init(&write_mutex, NULL); pthread_cond_init(&read_cond, NULL); pthread_cond_init(&write_cond, NULL); // 创建读者线程 for(i = 0; i < READERS_COUNT; i++) { reader_ids[i] = i; pthread_create(&readers[i], NULL, reader, (void*)&reader_ids[i]); } // 创建写者线程 for(i = 0; i < WRITERS_COUNT; i++) { writer_ids[i] = i; pthread_create(&writers[i], NULL, writer, (void*)&writer_ids[i]); } // 等待所有读者和写者线程结束 for(i = 0; i < READERS_COUNT; i++) { pthread_join(readers[i], NULL); } for(i = 0; i < WRITERS_COUNT; i++) { pthread_join(writers[i], NULL); } // 销毁互斥量和条件变量 pthread_mutex_destroy(&resource_mutex); pthread_mutex_destroy(&read_mutex); pthread_mutex_destroy(&write_mutex); pthread_cond_destroy(&read_cond); pthread_cond_destroy(&write_cond); return 0; } ``` 以上的代码实现了读者与写者问题的解决方案,其中使用互斥量和条件变量来保证资源的互斥访问和线程的同步。读者和写者通过互斥量和条件变量的配合,实现了对共享资源的有序访问。读者优先,即当有写者等待时,读者必须等待;而当没有写者等待时,读者可以直接访问资源。写者在没有读者访问或等待时,直接访问资源。通过通过互斥量和条件变量的配合,读者与写者问题得到了有效的解决。 ### 回答2: 读者与写者问题是一个典型的并发问题,它涉及到多个并发执行的读进程和写进程对共享资源的访问和修改。在操作系统中,可以使用信号量来实现读者和写者问题。 读者进程可以并发地访问共享资源,而写者进程必须在没有读者进程和其他写者进程访问时,独占地访问和修改共享资源。 下面是一个简单的C代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> sem_t mutex; // 用于控制对资源的访问 sem_t wrt; // 用于控制写进程的访问 int reader_count = 0; // 记录当前读者的数量 void *reader(void *arg) { int id = (int)arg; sem_wait(&mutex); // 互斥访问reader_count reader_count++; if (reader_count == 1) { sem_wait(&wrt); // 阻塞写进程 } sem_post(&mutex); // 执行读操作 printf("Reader %d is reading.\n", id); sem_wait(&mutex); // 互斥访问reader_count reader_count--; if (reader_count == 0) { sem_post(&wrt); // 释放写进程 } sem_post(&mutex); pthread_exit(NULL); } void *writer(void *arg) { int id = (int)arg; sem_wait(&wrt); // 阻塞读进程和其他写进程 // 执行写操作 printf("Writer %d is writing.\n", id); sem_post(&wrt); // 释放读进程和其他写进程 pthread_exit(NULL); } int main() { int num_readers = 3; // 读者进程数量 int num_writers = 2; // 写者进程数量 sem_init(&mutex, 0, 1); sem_init(&wrt, 0, 1); pthread_t readers[num_readers]; pthread_t writers[num_writers]; // 创建读者进程 for (int i = 0; i < num_readers; i++) { pthread_create(&readers[i], NULL, reader, (void *)i); } // 创建写者进程 for (int i = 0; i < num_writers; i++) { pthread_create(&writers[i], NULL, writer, (void *)i); } // 等待所有读者进程结束 for (int i = 0; i < num_readers; i++) { pthread_join(readers[i], NULL); } // 等待所有写者进程结束 for (int i = 0; i < num_writers; i++) { pthread_join(writers[i], NULL); } sem_destroy(&mutex); sem_destroy(&wrt); return 0; } ``` 在上述代码中,通过使用两个信号量mutex和wrt来实现对资源的互斥访问。其中mutex用于互斥访问reader_count,wrt用于控制写进程的访问。 在读者进程中,首先使用sem_wait(&mutex)来对reader_count进行互斥访问,然后判断reader_count的值。如果reader_count为1(表示当前没有其他读者进程访问资源),则使用sem_wait(&wrt)来阻塞写进程。接着执行读操作,然后再次使用sem_wait(&mutex)来互斥访问reader_count,减小reader_count的值,并判断reader_count是否为0(表示当前没有其他读者进程访问资源),如果是,则使用sem_post(&wrt)来释放写进程。 在写者进程中,使用sem_wait(&wrt)来阻塞读进程和其他写进程,执行写操作,然后使用sem_post(&wrt)来释放读进程和其他写进程。 在main函数中,通过创建和等待所有的读者和写者线程来模拟读者和写者的并发访问。 这样,就可以实现读者与写者问题的C代码实现
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值