目录
- 一、问题描述
- 二、问题分析
- 三、三种策略实现
- 1.读者优先策略
- 2. 读写公平策略
- 3.写者优先策略(后续更新)
一、问题描述
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程(只是读数据,不会对数据产生影响,而消费者读数据时,会将数据取走,因此不能两个消费者一起读数据)同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。
因此要求:
- 允许多个读者可以同时对文件执行读操作;
- 只允许一个写者往文件中写信息;
- 任一写者在完成写操作之前不允许其他读者或写者工作;
- 写者执行写操作前,应让已有的读者和写者全部退出。
二、问题分析
- 首先,分析问题中的同步互斥关系。读者和写者是互斥关系、写者和写者是互斥关系,而读者和读者不存在互斥关系。
- 其次,考虑读写进程并发运行的情况。若读者和写者并发地读数据或者写数据,我们应该优先处理读者进程,还是写者进程亦或是读写公平。
- 最后,设计信号量来控制互斥关系,以及读者、写者之间的优先执行策略。
三、三种策略实现
/* 本项目仅用于模拟解决读者-写者问题。
1.包含若干读者线程和写者线程用于模拟读者进程和写者进程。
2.包含一个单个资源临界缓冲区用于存放和读取数据。
3.分别实现读者优先、写者优先以及读写公平三种策略。
*/
1.读者优先策略
ReadHighPriority.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#define NUM_READERS 3 //读者进程数量
#define NUM_WRITERS 2 //写者进程数量
static int data = 0; //初始化临界缓存区为空
static int readers_count = 0; //记录读者进程数量
static HANDLE mutex; //用于实现读者进程对于readers_count变量的互斥访问
static HANDLE rw_semaphore; //用于实现读者和写者互斥访问临界缓冲区
static DWORD WINAPI Reader(LPVOID lpParam) {
int reader_id = *(int*)lpParam;
while (1) {
WaitForSingleObject(mutex, INFINITE);
readers_count++;
if (readers_count == 1) {
WaitForSingleObject(rw_semaphore, INFINITE);
}
ReleaseMutex(mutex);
printf("Reader %d is reading data: %d\n", reader_id, data);
Sleep(1000); // 模拟读取数据的耗时
WaitForSingleObject(mutex, INFINITE);
readers_count--;
if (readers_count == 0) {
ReleaseSemaphore(rw_semaphore, 1, NULL);
}
ReleaseMutex(mutex);
Sleep(2000); // 读者休息一段时间后再次读取数据
}
return 0;
}
DWORD WINAPI Writer(LPVOID lpParam) {
int writer_id = *(int*)lpParam;
while (1) {
WaitForSingleObject(rw_semaphore, INFINITE);
data++; // 写入数据
printf("Writer %d is writing data: %d\n", writer_id, data);
Sleep(2000); // 模拟写入数据的耗时
ReleaseSemaphore(rw_semaphore, 1, NULL);
Sleep(3000); // 写者休息一段时间后再次写入数据
}
return 0;
}
int main() {
// 创建互斥锁和读写信号量
mutex = CreateMutex(NULL, FALSE, NULL);
rw_semaphore = CreateSemaphore(NULL, 1, 1, NULL);
// 创建读者线程
HANDLE reader_threads[NUM_READERS];
int reader_ids[NUM_READERS];
for (int i = 0; i < NUM_READERS; i++) {
reader_ids[i] = i + 1;
reader_threads[i] = CreateThread(NULL, 0, Reader, &reader_ids[i], 0, NULL);
}
// 创建写者线程
HANDLE writer_threads[NUM_WRITERS];
int writer_ids[NUM_WRITERS];
for (int i = 0; i < NUM_WRITERS; i++) {
writer_ids[i] = i + 1;
writer_threads[i] = CreateThread(NULL, 0, Writer, &writer_ids[i], 0, NULL);
}
// 等待所有读者线程和写者线程结束
WaitForMultipleObjects(NUM_READERS, reader_threads, TRUE, INFINITE);
WaitForMultipleObjects(NUM_WRITERS, writer_threads, TRUE, INFINITE);
// 关闭句柄
CloseHandle(mutex);
CloseHandle(rw_semaphore);
return 0;
}
2. 读写公平策略
ReadrWriterEqualPriority.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#define NUM_READERS 3 //读者进程数量
#define NUM_WRITERS 2 //写者进程数量
static int data = 0; //初始化临界缓存区为空
static int readers_count = 0; //记录读者进程数量
static HANDLE mutex; //用于实现读者进程对于readers_count变量的互斥访问
static HANDLE rw_semaphore; //用于实现读者和写者互斥访问临界缓冲区
static HANDLE w_priority; //用于实现写优先
static DWORD WINAPI Reader(LPVOID lpParam) {
int reader_id = *(int*)lpParam;
while (1) {
WaitForSingleObject(w_priority, INFINITE);
WaitForSingleObject(mutex, INFINITE);
readers_count++;
if (readers_count == 1) {
WaitForSingleObject(rw_semaphore, INFINITE);
}
ReleaseMutex(mutex);
ReleaseSemaphore(w_priority, 1, NULL);
printf("Reader %d is reading data: %d\n", reader_id, data);
Sleep(1000); // 模拟读取数据的耗时
WaitForSingleObject(mutex, INFINITE);
readers_count--;
if (readers_count == 0) {
ReleaseSemaphore(rw_semaphore, 1, NULL);
}
ReleaseMutex(mutex);
Sleep(2000); // 读者休息一段时间后再次读取数据
}
return 0;
}
DWORD WINAPI Writer(LPVOID lpParam) {
int writer_id = *(int*)lpParam;
while (1) {
WaitForSingleObject(w_priority, INFINITE);
WaitForSingleObject(rw_semaphore, INFINITE);
data++; // 写入数据
printf("Writer %d is writing data: %d\n", writer_id, data);
Sleep(2000); // 模拟写入数据的耗时
ReleaseSemaphore(rw_semaphore, 1, NULL);
ReleaseSemaphore(w_priority, 1, NULL);
Sleep(3000); // 写者休息一段时间后再次写入数据
}
return 0;
}
int main() {
// 创建互斥锁和读写信号量
mutex = CreateMutex(NULL, FALSE, NULL);
rw_semaphore = CreateSemaphore(NULL, 1, 1, NULL);
w_priority = CreateSemaphore(NULL,1,1,NULL);
// 创建读者线程
HANDLE reader_threads[NUM_READERS];
int reader_ids[NUM_READERS];
for (int i = 0; i < NUM_READERS; i++) {
reader_ids[i] = i + 1;
reader_threads[i] = CreateThread(NULL, 0, Reader, &reader_ids[i], 0, NULL);
}
// 创建写者线程
HANDLE writer_threads[NUM_WRITERS];
int writer_ids[NUM_WRITERS];
for (int i = 0; i < NUM_WRITERS; i++) {
writer_ids[i] = i + 1;
writer_threads[i] = CreateThread(NULL, 0, Writer, &writer_ids[i], 0, NULL);
}
// 等待所有读者线程和写者线程结束
WaitForMultipleObjects(NUM_READERS, reader_threads, TRUE, INFINITE);
WaitForMultipleObjects(NUM_WRITERS, writer_threads, TRUE, INFINITE);
// 关闭句柄
CloseHandle(mutex);
CloseHandle(rw_semaphore);
CloseHandle(w_priority);
return 0;
}