Linux线程中写过生产者消费者模型,这次研究读者写者模型。

文章目录

  • 读者写者模型遵循的规则
  • 读者优先
  • 写者优先
  • 读者和写者公平竞争

读者写者模型遵循的规则

读者-写者模型同样遵循321规则:

  • 写-写互斥,即不能有两个写者同时进行写操作。
  • 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。
  • 读-读允许,读者和读者之间没有关系,即可以有一个或多个读者同时读。

读者优先

如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。而此时写者正在被阻塞,只有所有的读者都读完,写者才会被唤醒。

//读者优先
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <iostream>
using namespace std;struct data
{string str;
};//临界区数据,读者写者分别读和写入shareData
data shareData;//读优先保证当已经有读者在读时,后续的读者可以直接开始读操作
//当然,写者必须等没有读者读时才能写
sem_t mutex_readCount, mutex_write;
//读者的数量
int  readCount;//读者
void* Reader(void* param)
{printf("线程 %ud: 正在等待读\n",pthread_self());int readWait = rand()%5;   sleep(readWait);    //读者数量++sem_wait(&mutex_readCount);readCount++;if(readCount == 1){//当读者数量>0时,写者不能写sem_wait(&mutex_write);   }sem_post(&mutex_readCount);//读者进行读操作printf("线程 %ud: 开始进行读\n", pthread_self());cout<<"读者读出数据:"<<shareData.str<<endl;;printf("线程 %ud: 读取完毕\n", pthread_self());//读完以后,读者数量--sem_wait(&mutex_readCount);readCount--;if(readCount == 0){//读者数量为0,写者可以写了sem_post(&mutex_write);}sem_post(&mutex_readCount);pthread_exit(0);
}//写者
void* Writer(void* param)
{printf("线程 %ud: 正在等待写\n",pthread_self());int writeWait = rand()%5;sleep(writeWait);string& writeStr= ((data*)param)->str;//多个线程写时,使用mutex_write进行互斥sem_wait(&mutex_write);printf("线程 %ud: 开始写入:%s\n",pthread_self(),writeStr.c_str());  shareData.str=writeStr;printf("线程 %ud: 写完\n",pthread_self());    sem_post(&mutex_write);pthread_exit(0);
}int main()
{srand((unsigned)time(NULL));pthread_t tid1;pthread_t tid2;pthread_t tid3;pthread_t tid4;pthread_t tid5;readCount=0;shareData.str="默认值";sem_init(&mutex_readCount, 0, 1);sem_init(&mutex_write, 0, 1);readCount = 0;//创建几个线程,分别为写者和读者,进行测试pthread_create(&tid2, NULL, Reader, NULL);data w1;w1.str="abc";pthread_create(&tid1, NULL, Writer, (void*)&w1);pthread_create(&tid4, NULL, Reader, NULL);pthread_create(&tid5, NULL, Reader, NULL);data w2;w2.str="1234";pthread_create(&tid3, NULL, Writer, (void*)&w2);sem_destroy(&mutex_readCount);sem_destroy(&mutex_write);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);pthread_join(tid4,NULL);pthread_join(tid5,NULL);return 0;
}


写者优先

如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。

换句话说,如果一个读者A申请进行读操作,并且写者想进行写操作,此时A会与写者竞争锁,如果写者竞争成功则写者先写,后续来的写者由于多线程原因会处于等待状态(等前一个写者写完),只有当等待状态的写者数量为0时,读者A才可以进行读。
如果读者A竞争成功则A先读,后续的读者B仍然要与写者竞争。

//写者优先
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <iostream>
using namespace std;struct data
{string str;
};//临界区数据,读者写者分别读和写入shareData
data shareData;//写优先必须保证必须等写者都写完,读者才能读,所以用rwMutex来控制其关系
//用mutex_write信号量来控制写者和写者之间互斥关系,当有读者读时,写者不能写
//由于读者和读者之间没有关系,所以不需要锁
//mutex_writeCount和mutex_readCount分别对读者和写者数量进行原子操作
sem_t rwMutex, mutex_writeCount, mutex_readCount, mutex_write;
//写者的数量和读者的数量
int writeCount, readCount;
//mutex主要用处是避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex先释放,则一旦有写者,写者可马上获得资源RWMutex
sem_t mutex;//读者
void* Reader(void* param)
{printf("线程 %ud: 正在等待读\n",pthread_self());int readWait = rand()%5;sleep(readWait);   //读者获取rwMutex信号量,//读优先必须保证必须等写者都写完,读者才能读,所以写者先获取rwMutex,当全部写完后才释放//如果写者没释放读者就来读,读者会被挂起sem_wait(&mutex);sem_wait(&rwMutex);//读者数量++sem_wait(&mutex_readCount);readCount++;if(readCount == 1){//当读者数量>0时,写者不能写sem_wait(&mutex_write);  }sem_post(&mutex_readCount);//到这里,读者申请读成功,立刻释放rwMutex,这样后续的读者和写者就能竞争rwMutex了//并且由于mutex,写者可以避免和多个读者竞争rwMutexsem_post(&rwMutex);sem_post(&mutex);printf("线程 %ud: 开始进行读\n", pthread_self());//读者进行读操作cout<<"读者读出数据:"<<shareData.str<<endl;;printf("线程 %ud: 读取完毕\n", pthread_self());//读完以后,读者数量--sem_wait(&mutex_readCount);readCount--;if(readCount == 0){sem_post(&mutex_write);}sem_post(&mutex_readCount);pthread_exit(0);
}//写者
void* Writer(void* param)
{printf("线程 %ud: 正在等待写\n",pthread_self());int writeWait = rand()%5;sleep(writeWait);string& writeStr= ((data*)param)->str;   sem_wait(&mutex_writeCount);writeCount++;writeWait++;if(writeCount == 1){//已经有一个写者,获取rwMutex,当写者数量为0时释放它,读者才能读sem_wait(&rwMutex);}sem_post(&mutex_writeCount);//多个线程写时,使用mutex_write进行互斥sem_wait(&mutex_write);printf("线程 %ud: 开始写入:%s\n",pthread_self(),writeStr.c_str());  shareData.str=writeStr;printf("线程 %ud: 写完\n",pthread_self());    sem_post(&mutex_write);sem_wait(&mutex_writeCount);writeCount--;if(writeCount == 0) {sem_post(&rwMutex);}sem_post(&mutex_writeCount);pthread_exit(0);
}int main()
{srand((unsigned)time(NULL));pthread_t tid1;pthread_t tid2;pthread_t tid3;pthread_t tid4;pthread_t tid5;writeCount=readCount=0;shareData.str="默认值";sem_init(&rwMutex, 0, 1);sem_init(&mutex_writeCount, 0, 1);sem_init(&mutex_readCount, 0, 1);sem_init(&mutex_write, 0, 1);sem_init(&mutex, 0, 1);//创建几个线程,分别为写者和读者,进行测试pthread_create(&tid2, NULL, Reader, NULL);data w1;w1.str="abc";pthread_create(&tid1, NULL, Writer, (void*)&w1);pthread_create(&tid4, NULL, Reader, NULL);pthread_create(&tid5, NULL, Reader, NULL);data w2;w2.str="1234";pthread_create(&tid3, NULL, Writer, (void*)&w2);sem_destroy(&rwMutex);sem_destroy(&mutex_writeCount);sem_destroy(&mutex_readCount);sem_destroy(&mutex_write);sem_destroy(&mutex);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);pthread_join(tid4,NULL);pthread_join(tid5,NULL);return 0;
}


读者和写者公平竞争

上面两种方式都会导致读者或者写者饥饿,即读者一直读或者写者一直写的情况。下面解决这个问题,采取的策略是:

  • 读者和写者优先级相同;
  • 写者、读者互斥访问;
  • 只能⼀个写者访问临界区;
  • 可以有多个读者同时访问临街资源
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <iostream>
using namespace std;struct data
{string str;
};//临界区数据,读者写者分别读和写入shareData
data shareData;//读优先保证当已经有读者在读时,后续的读者可以直接开始读操作
//当然,写者必须等没有读者读时才能写
sem_t mutex_readCount, mutex_write;
//flag实现公平竞争
sem_t flag;//读者的数量
int  readCount;//读者
void* Reader(void* param)
{printf("线程 %ud: 正在等待读\n",pthread_self());int readWait = rand()%5;   sleep(readWait);    //在读之前,先和写者竞争flagsem_wait(&flag);//读者数量++sem_wait(&mutex_readCount);readCount++;if(readCount == 1){//当读者数量>0时,写者不能写sem_wait(&mutex_write);   }sem_post(&mutex_readCount);sem_post(&flag);//读者进行读操作printf("线程 %ud: 开始进行读\n", pthread_self());cout<<"读者读出数据:"<<shareData.str<<endl;;printf("线程 %ud: 读取完毕\n", pthread_self());//读完以后,读者数量--sem_wait(&mutex_readCount);readCount--;if(readCount == 0){//读者数量为0,写者可以写了sem_post(&mutex_write);}sem_post(&mutex_readCount);pthread_exit(0);
}//写者
void* Writer(void* param)
{printf("线程 %ud: 正在等待写\n",pthread_self());int writeWait = rand()%5;sleep(writeWait);string& writeStr= ((data*)param)->str;//在写之前,先和读者竞争flagsem_wait(&flag);//多个线程写时,使用mutex_write进行互斥sem_wait(&mutex_write);printf("线程 %ud: 开始写入:%s\n",pthread_self(),writeStr.c_str());  shareData.str=writeStr;printf("线程 %ud: 写完\n",pthread_self());    sem_post(&mutex_write);sem_post(&flag);pthread_exit(0);
}int main()
{srand((unsigned)time(NULL));pthread_t tid1;pthread_t tid2;pthread_t tid3;pthread_t tid4;pthread_t tid5;readCount=0;shareData.str="默认值";sem_init(&mutex_readCount, 0, 1);sem_init(&mutex_write, 0, 1);sem_init(&flag, 0, 1);readCount = 0;//创建几个线程,分别为写者和读者,进行测试pthread_create(&tid2, NULL, Reader, NULL);data w1;w1.str="abc";pthread_create(&tid1, NULL, Writer, (void*)&w1);pthread_create(&tid4, NULL, Reader, NULL);pthread_create(&tid5, NULL, Reader, NULL);data w2;w2.str="1234";pthread_create(&tid3, NULL, Writer, (void*)&w2);sem_destroy(&mutex_readCount);sem_destroy(&mutex_write);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);pthread_join(tid4,NULL);pthread_join(tid5,NULL);return 0;
}

对⽐读者优先策略,可以发现,读者优先中只要后续有读者到达,读者就可以进⼊读者队列, ⽽写者必须等待,直到没有读者到达。
没有读者到达会导致读者队列为空,即 readCount ==0,此时写者才可以进⼊临界区执⾏写操作。⽽这⾥ flag 的作⽤就是阻⽌读者的这种特殊权限(特殊权限是只要读者到达,就可以进⼊读者队列)。

读者写者模型---读优先与写优先相关推荐

  1. AT89S8253片内EEPROM字节读、字节写、页读、页写驱动代码、注意事项及注释

    在编写AT89S8253片内EEPROM读写驱动程序时,要特别注意数据读写指令MOVX: 当EECON寄存器的EEMEN位置位时,MOVX访问EEPROM: 当EECON寄存器的EEMEN位清零时,M ...

  2. 操作系统 读者写者问题的实现(C++ 读者优先、写者优先)

    通过信号量机制和相应的系统调用,用于线程的互斥和同步,实现读者写者问题.利用信号量机制,实现读者写者问题. 在windows 10环境下,创建一个控制台进程,此进程包含n个线程.用这n个线程来表示n个 ...

  3. 利用PV操作实现读者-写者问题(读者优先、写者优先)

    .读者优先 1.写者.读者互斥访问文件资源. 2.多个读者可以同时访问文件资源. 3.只允许一个写者访问文件资源. .算法 Program reders writers; Var r_w_w:sema ...

  4. 计算机操作系统读者和写者模型的简单介绍以及思考

    读者和写者 读写两组进程,共享一个文件,多个读者可以同时访问文件,多个写者不可以同时访问文件,写者和读者也不可以同时访问文件 共享读:独占写 特征:1,资源被谁占有:2,写者改变资源,读者不改变资源 ...

  5. delphi usb 读写_写作论语 | 崔嵘:写我所读——国外整本书阅读中读写结合的理论与实践(上)...

    崔嵘简介 崔嵘,博士,首都师范大学初等教育学院副教授.硕士研究生导师, 澳大利亚弗林德斯大学教育学院客座副教授,美国明尼苏达大学访问学者,北京市语文现代化研究会秘书长.全国名师工作室联盟学术委员会学术 ...

  6. 长知识啦——自己动手写分类模型

    文章目录 二分类模型 多分类模型 本次博文是向大家伙分享一下自己写的关于分类模型的Python代码,阅读时长可能比较长,如果文中出现错误也请大家及时批评指正,共同学习,另外,自己写的模型,尤其是sof ...

  7. 进程P1、P2、P3共享一个表格F,P1对F只读不写,P2对F只写不读,P3对F先读后写。进程可同时读F,但有进程写时,其他进程不能读和写。

    进程P1.P2.P3共享一个表格F,P1对F只读不写,P2对F只写不读,P3对F先读后写.进程可同时读F,但有进程写时,其他进程不能读和写.要求:(1)正常运行时不能产生死锁.(2)F的并发度要高. ...

  8. 小白成长以及学习轨迹:我的四年大学,写给正在读大学的你

    前阵子有些读者问我大学期间的学习路线,说他自己现在有点迷茫.说实话,对于学习路线这种文章,一抓一大堆,我也不大喜欢去建议别人究竟该怎么学习,学习顺序之类的.不过对于大学,很多人进入大学的时候,可能都是 ...

  9. 使用ReaderWriterLock类实现多用户读/单用户写同步

    使用ReaderWriterLock类实现多用户读/单用户写同步[1] 2015-03-12 应用程序在访问资源时是进行读操作,写操作相对较少.为解决这一问题,C#提供了System.Threadin ...

最新文章

  1. 雨林木风爱好者GHOSTXP装机版_NTFS_SP3_2010_03
  2. ajax catch,promise记得写上catch
  3. python怎么安装myqr模块-python二维码操作:对QRCode和MyQR入门详解
  4. DATAGRID学习
  5. java编程点滴(3)--ubuntu下jdk的配置
  6. 2019年10个最受欢迎的JavaScript动画库!
  7. TeamCity和GitLab整合
  8. @transactional 接口_Spring事物(@transactional注解)在什么情况下会失效,为什么?...
  9. linux之多任务的同步与互斥
  10. matplotlib —— 添加文本信息(text)
  11. 鸟哥的linux私房菜有乌班图,折腾Ubuntu的一些summary--初装Ubuntu18和重装Ubuntu18
  12. 读大道至简第二章感悟
  13. c#中queue的用法
  14. 3dmax2020渲染器下载3dmax2020渲染器VRay4.2下载安装教程
  15. Java后端学习路线图,你真的只需要这一张
  16. matlab神经网络训练方法,matlab神经网络训练图
  17. 广义线性模型的计算机应用技术学院,SPSS数据分析—广义线性模型
  18. win10终端中如何切换磁盘
  19. php写poc,0day Poc编写指南(实战篇)
  20. MAC无法重装anaconda3

热门文章

  1. matlab的exp函数学习
  2. 基础的http协议构成
  3. 贝叶斯网专题11:参数学习之极大似然估计
  4. win10忘记开机密码怎么办?
  5. 大数据平台监控指南(附技术选型、监控指标)
  6. Linux服务器Anaconda安装Pytorch(注意,前方有大坑)
  7. 骰子算法 php,算法题--骰子游戏
  8. unity获取手机IMEI码
  9. 某计算机无法访问域名,在某台主机上无法访问域名为www.bbb.cn的网站,而局域网中的其他主机可..._考试资料网...
  10. 麦当劳McDonalds 社会责任验厂(SWA)审核指南