读者写者模型

读者写者模型

读者写者

“读者-写者”问题是经典的同步问题,常用于解决多线程访问共享资源的同步控制。此问题主要是确保在多个线程并发访问共享资源(如文件或数据库)时,避免数据不一致。通常有两种策略:

读者优先:允许多个读者同时访问资源,但写者必须等待。
写者优先:写者一旦想要写入,所有读者都需要等待,优先满足写者请求。

读者优先

代码

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

sem_t resource;     // 资源信号量,确保写者独占访问
sem_t read_count_sem; // 读计数器信号量,保证对读者计数的互斥访问
int read_count = 0; // 读者计数器

void *reader(void *arg) {
    int reader_id = *(int *)arg;
    free(arg);

    while (1) {
        // 进入临界区,增加读者计数
        sem_wait(&read_count_sem);
        read_count++;
        if (read_count == 1) {
            // 第一个读者请求访问资源,阻止写者
            sem_wait(&resource);
        }
        sem_post(&read_count_sem);

        // 模拟读操作
        printf("Reader %d is reading\n", reader_id);
        sleep(1); // 模拟读的耗时

        // 退出临界区,减少读者计数
        sem_wait(&read_count_sem);
        read_count--;
        if (read_count == 0) {
            // 最后一个读者离开,允许写者访问资源
            sem_post(&resource);
        }
        sem_post(&read_count_sem);

        sleep(1); // 让其他线程有机会运行
    }
    return NULL;
}

void *writer(void *arg) {
    int writer_id = *(int *)arg;
    free(arg);

    while (1) {
        // 请求独占资源访问
        sem_wait(&resource);

        // 模拟写操作
        printf("Writer %d is writing\n", writer_id);
        sleep(2); // 模拟写的耗时

        // 释放资源
        sem_post(&resource);

        sleep(1); // 让其他线程有机会运行
    }
    return NULL;
}

int main() {
    pthread_t r_threads[5], w_threads[2];

    // 初始化信号量
    sem_init(&resource, 0, 1);
    sem_init(&read_count_sem, 0, 1);

    // 创建读者线程
    for (int i = 0; i < 5; i++) {
        int *id = malloc(sizeof(int));
        *id = i + 1;
        pthread_create(&r_threads[i], NULL, reader, id);
    }

    // 创建写者线程
    for (int i = 0; i < 2; i++) {
        int *id = malloc(sizeof(int));
        *id = i + 1;
        pthread_create(&w_threads[i], NULL, writer, id);
    }

    // 等待线程结束
    for (int i = 0; i < 5; i++) {
        pthread_join(r_threads[i], NULL);
    }
    for (int i = 0; i < 2; i++) {
        pthread_join(w_threads[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&resource);
    sem_destroy(&read_count_sem);

    return 0;
}

读者优先

代码说明:

  • 资源信号量 resource:用于保证写者独占资源的访问权限。
  • 读者计数器信号量 read_count_sem:保证对 read_count 的访问互斥。
  • 读者函数 reader:每次读取前增加 read_count,第一个读者进入时阻止写者。
    完成读取后减少 read_count,最后一个读者离开时释放写者的资源。
  • 写者函数 writer:写者获取 resource,独占资源访问。
  • 写入完成后释放 resource,允许其他读者或写者进入。

运行效果:

多个读者可以同时访问,且在没有写者时可以连续读取。
一旦有写者请求资源,写者会等待所有读者退出后独占资源。

写者优先

代码

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

sem_t resource;           // 控制资源的信号量
sem_t read_count_sem;     // 控制读者计数的信号量
sem_t write_count_sem;    // 控制写者计数的信号量
int read_count = 0;       // 当前读者计数
int write_count = 0;      // 当前写者计数

void *reader(void *arg) {
    int reader_id = *(int *)arg;
    free(arg);

    while (1) {
        // 若有写者等待,读者需等待
        sem_wait(&write_count_sem);
        sem_post(&write_count_sem);

        // 增加读者计数
        sem_wait(&read_count_sem);
        read_count++;
        if (read_count == 1) {
            sem_wait(&resource); // 阻止写者
        }
        sem_post(&read_count_sem);

        // 模拟读操作
        printf("Reader %d is reading\n", reader_id);
        sleep(1);

        // 减少读者计数
        sem_wait(&read_count_sem);
        read_count--;
        if (read_count == 0) {
            sem_post(&resource); // 最后一个读者离开后释放资源
        }
        sem_post(&read_count_sem);

        sleep(1); // 让其他线程有机会运行
    }
    return NULL;
}

void *writer(void *arg) {
    int writer_id = *(int *)arg;
    free(arg);

    while (1) {
        // 增加写者计数
        sem_wait(&write_count_sem);
        write_count++;
        if (write_count == 1) {
            sem_wait(&resource); // 第一个写者到来时阻止读者
        }
        sem_post(&write_count_sem);

        // 请求资源独占访问
        printf("Writer %d is writing\n", writer_id);
        sleep(2);

        // 减少写者计数
        sem_wait(&write_count_sem);
        write_count--;
        if (write_count == 0) {
            sem_post(&resource); // 最后一个写者离开后允许读者进入
        }
        sem_post(&write_count_sem);

        sleep(1); // 让其他线程有机会运行
    }
    return NULL;
}

int main() {
    pthread_t r_threads[5], w_threads[2];

    // 初始化信号量
    sem_init(&resource, 0, 1);
    sem_init(&read_count_sem, 0, 1);
    sem_init(&write_count_sem, 0, 1);

    // 创建读者线程
    for (int i = 0; i < 5; i++) {
        int *id = malloc(sizeof(int));
        *id = i + 1;
        pthread_create(&r_threads[i], NULL, reader, id);
    }

    // 创建写者线程
    for (int i = 0; i < 2; i++) {
        int *id = malloc(sizeof(int));
        *id = i + 1;
        pthread_create(&w_threads[i], NULL, writer, id);
    }

    // 等待线程结束
    for (int i = 0; i < 5; i++) {
        pthread_join(r_threads[i], NULL);
    }
    for (int i = 0; i < 2; i++) {
        pthread_join(w_threads[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&resource);
    sem_destroy(&read_count_sem);
    sem_destroy(&write_count_sem);

    return 0;
}

写者优先

代码说明:

  • 信号量 resource:控制对资源的独占访问。
  • 信号量 read_count_sem:控制对读者计数器的互斥访问。
  • 信号量 write_count_sem:控制对写者计数器的互斥访问。
  • 读者函数 reader:检查是否有写者在等待,若有,读者会等待。每当第一个读者到来时,会阻止写者。
    读操作完成后,如果是最后一个读者,则释放资源以允许写者访问。
  • 写者函数 writer:写者到来时增加 write_count,第一个写者到达时阻止读者。
    写操作完成后,减少 write_count,最后一个写者离开时释放资源以允许读者进入。

运行效果

当有写者请求访问时,写者优先于读者进行访问。
若写者和读者同时请求,写者会优先完成写操作,读者等待直至写者完成。

posted @ 2025-01-02 11:27  Arisf  阅读(6)  评论(0编辑  收藏  举报