【C/C++解决读者-写者问题】

一、问题描述

有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程(只是读数据,不会对数据产生影响,而消费者读数据时,会将数据取走,因此不能两个消费者一起读数据)同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。
因此要求:

  1. 允许多个读者可以同时对文件执行读操作;
  2. 只允许一个写者往文件中写信息;
  3. 任一写者在完成写操作之前不允许其他读者或写者工作;
  4. 写者执行写操作前,应让已有的读者和写者全部退出。

二、问题分析

  • 首先,分析问题中的同步互斥关系。读者和写者是互斥关系、写者和写者是互斥关系,而读者和读者不存在互斥关系。
  • 其次,考虑读写进程并发运行的情况。若读者和写者并发地读数据或者写数据,我们应该优先处理读者进程,还是写者进程亦或是读写公平。
  • 最后,设计信号量来控制互斥关系,以及读者、写者之间的优先执行策略。

三、三种策略实现

/*  本项目仅用于模拟解决读者-写者问题。
    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;
}

3.写者优先策略(后续更新)

猜你喜欢

转载自blog.csdn.net/wddkxg/article/details/131427742