C语言模拟读者写者(读者优先、单轮读写)

一、问题描述

  1. 主函数根据当前进程id生成一个随机数。
  2. 写进程以线程参数的形式获取此随机数并将其写入到共享数据中,即 share_data = *(int *)arg;,写入后退出。
  3. 累计五个读者需要依此将此共享数据在控制台输出,即 printf("%d\n", share_data);,输出后退出。

二、代码

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <stdlib.h>

int count = 0; // 读者计数器

pthread_mutex_t mutex; // 全局锁 保证读写互斥与写写互斥
pthread_mutex_t mutex_count; // 读者锁 保证读者互斥更新count

int share_data; // 读者写者的共享数据

void *Writer(void *arg) {
    
    
    pthread_mutex_lock(&mutex); // 抢全局锁

    share_data = *(int *)arg; // 生产数据

    pthread_mutex_unlock(&mutex); // 释放全局锁
    pthread_exit(NULL);
}

void *Reader(void *arg) {
    
    
    pthread_mutex_lock(&mutex_count); // 抢读者锁
    if (count == 0) {
    
    
        pthread_mutex_lock(&mutex); // 抢全局锁
    }
    count++;
    pthread_mutex_unlock(&mutex_count); // 释放读者锁

    printf("%d\n", share_data); // 消耗数据

    pthread_mutex_lock(&mutex_count); // 抢读者锁
    count--;
    if (count == 0) {
    
    
        pthread_mutex_unlock(&mutex); // 释放全局锁
    }
    pthread_mutex_unlock(&mutex_count); // 释放读者锁
    pthread_exit(NULL);
}

int main() {
    
    
    /* 初始化互斥锁及线程信息 */
    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_init(&mutex_count, NULL);
    pthread_t thread[6];
    memset(thread, 0, 6 * sizeof(pthread_t));

    /* 以下12行代码用于生成一个需要交给写者写入的随机数 无需关注具体实现 */
    int data;
    int log_fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0755);
    srand(getpid());
    data = rand() % 10; // 写进程需要写入的一个十以内的随机数
    for (int i = 0; i < 5; i++) {
    
    
        char buffer[3];
        buffer[0] = data + 48; // 随机数
        buffer[1] = 10; // 换行
        buffer[2] = 0;
        write(log_fd, buffer, strlen(buffer));
    }
    close(log_fd);

    /* 创建一个写者线程 */
    for (int i = 0; i < 1; i++) {
    
    
        pthread_create(&thread[i], NULL, Writer, (void *)(&data)); // 将读者待写入的数据以线程参数的形式传递给写者
    }

    /* 虽然为读优先 但因为只循环一轮 所以需要通过sleep让写进程先执行 */
    sleep(1);

    /* 创建五个读者线程 */
    for (int i = 1; i < 6; i++) {
    
    
        pthread_create(&thread[i], NULL, Reader, NULL);
    }

    /* 所有的读者写者都是可结合态线程 需要通过pthread_join回收 */
    for (int i = 0; i < 6; i++) {
    
    
        pthread_join(thread[i], NULL);
    }

    /* 销毁互斥锁 */
    pthread_mutex_destroy(&mutex);
    pthread_mutex_destroy(&mutex_count);

    return 0;
}

三、评测脚本

#!/bin/bash

# 标准输出重定向到error.txt 标准错误输出重定向到标准输出
gcc ./main.c -o exe -w -lpthread >error.txt 2>&1

if [ -f exe ]; then
  # 编译成功
  ./exe >result.txt 2>error.txt
  # 运行成功
  if [ ! -s error.txt ]; then
    diff result.txt log.txt >error.txt 2>&1
    if [ "$?" == "0" ]; then
      echo "读者读取数据完成"
    else
      echo "读者读取数据失败"
      echo -n "写者写入的数据为:"
      cat log.txt
      echo -n "您编写的代码中读者读取的数据为:"
      cat result.txt
    fi
  else
    echo "程序执行错误"
    echo -n "错误原因:"
    cat error.txt
  fi
else
  echo "编译程序失败"
  echo -n "错误原因:"
  cat error.txt
fi

rm -rf case result.txt log.txt error.txt >/dev/null 2>&1

猜你喜欢

转载自blog.csdn.net/qq_43686863/article/details/129711175