读者写者问题读者优先 C语言实现代码

本博客代码摘自Mic_H,我小小地修改了一些。
本博客记录自己的学习,疑问和理解。欢迎大家交流和指教。
作者原博客链接
我的代码和运行结果:

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <accctrl.h>
#include <time.h>
unsigned int readcount = 0;
bool p_ccontinue = true; //控制程序结束
HANDLE RSemaphore; //改变readcount值时互斥
HANDLE WSemaphore; //写互斥
DWORD WINAPI Writer(LPVOID); //写者线程
DWORD WINAPI Reader(LPVOID); //读者线程
int main()
{
    RSemaphore = CreateSemaphore(NULL,1,1,NULL);
    WSemaphore = CreateSemaphore(NULL,1,1,NULL);
    const unsigned short Writer_COUNT = 3;//写者数量
    const unsigned short Reader_COUNT = 8;//读者数量
    const unsigned short THREADS_COUNT = Writer_COUNT+Reader_COUNT;
    HANDLE hThreads[THREADS_COUNT]; //各线程的 handle
    DWORD writerID[Writer_COUNT]; //写者线程的标识符
    DWORD readerID[Reader_COUNT]; //读者线程的标识符
 
    srand(time(0));
    int writer_count = 0;
    int reader_count = 0;
    for(int i = 0; i < Writer_COUNT + Reader_COUNT; i++)
    {
        int ran = rand()%10;
        if((ran < 5) && (writer_count < Writer_COUNT))//Writer
        {
            hThreads[i]=CreateThread(NULL,0,Writer,NULL,0,&writerID[writer_count]);
            if (hThreads[i]==NULL) return -1;
            writer_count++;
        }
        else if((ran >= 5) && (reader_count < Reader_COUNT))//Reader
        {
            hThreads[i]=CreateThread(NULL,0,Reader,NULL,0,&readerID[reader_count]);
            if (hThreads[i]==NULL) return -1;
            reader_count++;
        }
        Sleep(500);//等待500ms
    }
    while(p_ccontinue)
    {
        if(getchar())  //按回车后终止程序运行
        {
            p_ccontinue = false;
        }
    }
    return 0;
}
//写者
DWORD WINAPI Writer(LPVOID lpPara)
{
    while(p_ccontinue)
    {
        printf("\n%d is waiting to write...\n",GetCurrentThreadId());
        WaitForSingleObject(WSemaphore,INFINITE);//P(w)在读或在写时,写者阻塞
        printf("\n**  writer %d got the control\n",GetCurrentThreadId());
        //write...
        printf("\n%d is writing...\n",GetCurrentThreadId());
        Sleep(1500);
        printf("\n--- %d have finished the writing\n",GetCurrentThreadId());
        ReleaseSemaphore(WSemaphore,1,NULL);//V(w)写完,唤醒阻塞的读者或写者
        return 0;//结束此线程
    }
    return 0;
}
//读者
DWORD WINAPI Reader(LPVOID lpPara)
{
    while(p_ccontinue)
    {
        printf("\n%d is waiting to read...\n",GetCurrentThreadId());
        WaitForSingleObject(RSemaphore,INFINITE);//P(x)临界区互斥,所有读者修改readcount
        readcount++;
        if(readcount == 1)//第一个读,要等已经在写的写者写完才可以开始读
            WaitForSingleObject(WSemaphore,INFINITE);//P(w)有写时,读者阻塞
        //同时读,故要在Read()之前V(x)
        ReleaseSemaphore(RSemaphore,1,NULL);//V(x)
        //read...
        printf("\n%d is reading...\n",GetCurrentThreadId());
        Sleep(1500);
        printf("\n--- %d have finished the reading\n",GetCurrentThreadId());
        WaitForSingleObject(RSemaphore,INFINITE);//P(x)
        readcount--;
        if(readcount== 0)
        {
            printf("\n----- All Readers done\n");
            ReleaseSemaphore(WSemaphore,1,NULL);//V(w)都不读,唤醒阻塞的写者
        }
        ReleaseSemaphore(RSemaphore,1,NULL);//V(x)
        return 0;//结束此线程
    }
    return 0;
}
 
13656 is waiting to write...

**  writer 13656 got the control

13656 is writing...

33596 is waiting to read...

7620 is waiting to read...

--- 13656 have finished the writing

33596 is reading...

33596 is reading...

7620 is reading...

29964 is waiting to read...

29964 is reading...

31876 is waiting to write...

34616 is waiting to read...

34616 is reading...

--- 33596 have finished the reading

--- 33596 have finished the reading

--- 29964 have finished the reading

--- 33596 have finished the reading

--- 29964 have finished the reading
--- 7620 have finished the reading

32608 is waiting to read...

32608 is reading...

7800 is waiting to write...

--- 34616 have finished the reading

--- 32608 have finished the reading

----- All Readers done

**  writer 31876 got the control

31876 is writing...

--- 31876 have finished the writing

**  writer 7800 got the control

7800 is writing...

--- 7800 have finished the writing

以下是我自己实验的一些薄浅的理解和疑问(本人小白,写错了不要喷,欢迎大家指教)。
理解:1.通过srand获得随机数种子,ran获得随机数,经if语句的两个条件,决定创建是写线程还是读线程。但是这个for循环i是小于3+8的,如果write_count为3,即写线程创建完成了,但是此后有一个或者几个ran<5,既不会创建写线程,也不会创建读线程。所以不会创建8个读线程,大概率会小于8个读线程。(运行20次左右就出现一次)
2.写线程中的ReleaseSemaphore(WSemaphore,1,NULL)唤醒的是阻塞的读者或写者。我修改之后的程序运行,如果xxxx is waiting to read 在 xxxx is waiting 之前,这个写线程是先被调度的,所以先输出xxxx is writing 后输出 xxxx is reading。注意:绝对读者优先此处唤醒的是阻塞的读者。
3.sleep(500)可以表示写、读线程进入的过程。sleep(1500)可以表示写线程写的过程,读线程读的过程。
疑问:
1.for循环中的Writer_COUNT + Reader_COUNT改成THREADS_COUNT(极少时候没改变这个也会出现),部分xxxx is reading就会输出两次,但是xxxx is waiting to read只出现一次。(如图的33596就是这样)这个疑问不知道是怎么回事。读线程和写线程函数部分,我加了一些单词或者换成中文,前几次运行结果均会出现乱码,格式错误等问题,多运行几次后,每4.5次就会出现一次乱码(估计可能是我vc6++是中文破译版的问题)。
因为是刚刚学习操作系统中各种问题的代码实现,就有很多系统函数不知道。所以我做了一些笔记(字难看,勿喷),
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以下是一个简单的读者写者问题(写者优先)的C语言代码,其中写者具有优先权: ``` #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define NUM_READERS 5 #define NUM_WRITERS 2 sem_t reader_mutex, writer_mutex, read_mutex; int readers = 0, writers = 0; void *reader(void *arg) { int id = *(int *)arg; while (1) { sem_wait(&reader_mutex); readers++; if (readers == 1) { sem_wait(&write_mutex); } sem_post(&reader_mutex); sem_wait(&read_mutex); printf("Reader %d is reading...\n", id); sem_post(&read_mutex); sem_wait(&reader_mutex); readers--; if (readers == 0) { sem_post(&write_mutex); } sem_post(&reader_mutex); sleep(rand() % 3); } } void *writer(void *arg) { int id = *(int *)arg; while (1) { sem_wait(&writer_mutex); writers++; if (writers == 1) { sem_wait(&read_mutex); } sem_post(&writer_mutex); sem_wait(&write_mutex); printf("Writer %d is writing...\n", id); sem_post(&write_mutex); sem_wait(&writer_mutex); writers--; if (writers == 0) { sem_post(&read_mutex); } sem_post(&writer_mutex); sleep(rand() % 3); } } int main() { pthread_t readers[NUM_READERS], writers[NUM_WRITERS]; int reader_ids[NUM_READERS], writer_ids[NUM_WRITERS]; int i; sem_init(&reader_mutex, 0, 1); sem_init(&writer_mutex, 0, 1); sem_init(&read_mutex, 0, 1); for (i = 0; i < NUM_READERS; i++) { reader_ids[i] = i; pthread_create(&readers[i], NULL, reader, &reader_ids[i]); } for (i = 0; i < NUM_WRITERS; i++) { writer_ids[i] = i; pthread_create(&writers[i], NULL, writer, &writer_ids[i]); } for (i = 0; i < NUM_READERS; i++) { pthread_join(readers[i], NULL); } for (i = 0; i < NUM_WRITERS; i++) { pthread_join(writers[i], NULL); } sem_destroy(&reader_mutex); sem_destroy(&writer_mutex); sem_destroy(&read_mutex); return 0; } ``` 在此代码中,我们使用了三个信号量:reader_mutex,writer_mutex和read_mutex。reader_mutex保护读者计数器,writer_mutex保护写者计数器,read_mutex保护读操作。 读者线程执行以下步骤: 1. 获取reader_mutex,增加读者计数器 2. 如果是第一个读者,则获取write_mutex,以防止写者进入 3. 释放reader_mutex 4. 获取read_mutex,执行读操作 5. 释放read_mutex 6. 获取reader_mutex,减少读者计数器 7. 如果是最后一个读者,则释放write_mutex 写者线程执行以下步骤: 1. 获取writer_mutex,增加写者计数器 2. 如果是第一个写者,则获取read_mutex,以防止读者进入 3. 释放writer_mutex 4. 获取write_mutex,执行写操作 5. 释放write_mutex 6. 获取writer_mutex,减少写者计数器 7. 如果是最后一个写者,则释放read_mutex 通过使用这些信号量和计数器,我们确保了写者具有优先权,以避免读者饥饿,并确保读者和写者能够安全地访问共享资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值