锁机制:读者写者问题 Linux C

article/2025/9/30 9:54:28

最近碰到一些锁机制的问题,想起大三的时候做过的一个小课设,记录复习一下。

问题描述:

一个数据文件可以被多个进程共享,其中,有些进程要求读(reader进程),而另一些进程要求对数据进行写或修改(writer进程)。允许多个reader进程同时读一个共享对象,因为读操作不会使数据文件混乱,但绝不允许一个writer进程和其他reader进程或writer进程同时访问共享对象。所谓“读者-写者问题”是指保证一个writer进程必须与其他进程互斥访问共享对象的同步问题。

本课题所设计的系统要求实现以下功能:

创建一个文件sharefile作为共享数据存放的文件。

创建2个reader进程及2个writer进程,4个进程共享使用文件sharefile。

使用信号量机制,编写“读者-写者问题”的实现代码,使得每个writer进程与其他进程互斥访问共享文件sharefile。

要求给出编译所用到的makefile文件。

构思与解决过程

方法一

1、代码结构与相关知识

此处将代码分为四个部分,分别是文件锁操作lock_set.c ,线程控制操作(包含文件读写及一系列核心操作)threads.c ,具体线程创建及信号量控制writers.c, reads.c,以及makefile。

在开展此课程设计之前重点复习了线程控制与线程间通信,尤其是信号量部分。在文件读写模块采用了底层文件读写技术,及文件锁的运用。

一、关于信号量:

此处需要两种信号量:

1.控制读的资源信号量(read_mutex),理论上可以有无数个。

2.控制写的资源信号量(write_mutex),只能有一个。

3.在进行读的时候除了要对read_mutex进行p操作外还需要先对write_mutex进行p操作,以此保证写进程的唯一占有资源。(此处采用读者优先算法)。

二、关于读者写者之间的同步细节实现问题

为方便操作起见,在此自定义了一个文件状态描述符(代码如下):

int fileState=0;//show file state (0:no operator , 1:writing , 2:reading)

即在描述符为0时表示当前无进程对其操作;在为1时表示有线程在对此文件进行写操作,此时读者线程需进行等待;在为2时表示有读者进程对文件进行读操作,此时写进程需要等待。详细描述如下:

1,在进入读者线程时需要对文件描述符进行检测,若不满足读文件条件则等待并且每隔一段时间进行探测,间隔时间可根据实际环境进行修改。而在检测条件通过后根据文件是否成功打开需要对文件状态描述符进行修改,代码描述如下:

//judge fileStatewhile(fileState==1){printf("this file using by writer! waiting...(%d)",getpid());sleep(1);}int fr=open("./sharefile",O_RDONLY);if(fr==-1){perror("error: open file!\n");pthread_exit(NULL) ;}//modify the fileStatefileState=2;

2,在进入写者线程时同样需要进行文件状态监测以及文件状态描述符的修改,其与读者线程类似。(代码如下):

//judge fileStatewhile(fileState==2){printf("this file using by writer! waiting...(%d)",getpid());sleep(1);}//1.open fileint fw=open("./sharefile",O_CREAT|O_WRONLY|O_APPEND,0600);if(fw==-1){perror("error: open file!\n");pthread_exit(NULL) ;}//modify the fileStatefileState=1;

 

方法二:

经测试发现方法一有一定的局限性,比如为了分享同一个文件状态码导致体系内所有线程只能在一个进程下运行。故在此运用系统API对文件进行上锁解锁等相关操作。

1、解决思路如下:

在此启用两个进程reads,writers,分别产生相应数量的子线程模拟多线程的读写协调问题。比如在此让reads创建2个读线程,writers产生2个写线程,4个线程同时对同一个文件进行相应操作。读写两类线程间运用文件锁机制进行协调,而同一类线程间运用信号量进行协调,其中读进程间是可以同时进行的,所以实际需要运用信号量同步的是写线程之间。而为了模拟实际操作中的随机性,在此让每个读或写线程运行时进行随机时间挂起,以此来让其他线程进入冲突解决状态(在发生冲突的情况下)。

2、核心代码如下

//1.open file int fw=open("./sharefile",O_CREAT|O_WRONLY|O_APPEND,0600);	if(fw==-1){perror("error: open file!\n");pthread_exit(NULL) ;}//modify the fileState//fileState=1;//function 2 (using system API)//add F_WRLCKlock_set(fw,F_WRLCK);int tnum=(int)arg;int writeSize=0;char buf[bufSize];//printf("          I'm writer, sem NO:%d!\n",tnum);//p operatorsem_wait(&sem_W[tnum]);char str[50];strcpy(str,"my thread number is:");char strTail[10];char wget;int count=0;memset(buf,0,bufSize);//clear buf String//2 auto input from argumentsprintf(strTail,"%d",getpid());//整数转换字符串strcat(str,strTail);//get localTimetime_t timep;time(&timep);strcat(str,ctime(&timep));strcpy(buf,str);		//2.model system delay lead to timeout(sleep)delay_t=(int)(rand()*delayTimeRange/RAND_MAX)+1;printf("         I'm writer, thread NO:%d ,now i will sleep for %d second!\n",getpid(),delay_t);sleep(delay_t);printf("     inputed String :%s (length:%d)\n",buf,(int)strlen(buf));//begin write to filewrite(fw,buf,strlen(buf));//unlocklock_set(fw,F_UNLCK);close(fw);//modify the fileState//fileState=0;printf("write success!TNO.%d\n",getpid());pthread_exit(NULL) ;

实验结果截图及解释

运行结果截图:

1读者写者之间的冲突解决

T1创建两个写者线程

T2创建四个读者线程(为了让实验体现更加清晰在此启用四个读者线程)

可以看到图片展示了在读者进程与写者进程簇同时对文件进行操作时会有相应的避让等待操作,即在两类线程之间读写时会对文件施加建议锁或者是强制性锁,在对文件操作完后释放锁。

2写者与写者之间的冲突解决:

可以看到在两个写者进程簇对同一个文件进行写入操作遇到冲突时,后来者需要等待操作,该操做基于系统文件强制性锁实现。

3,读者与读者之间(读者与读者之间读取文件时施加的是建议锁,互不干扰。)

4读写文件(共享文件)记录如下:

(5)思路总结:

在以上同一类进程下产生了多个线程,在此除了协调不同进程间对文件的操作外还需要借助信号量解决同一进程下的不同线程间协调一致性的问题,否则会导致线程间运行结果输出混乱的问题。解决代码如下:(在此举例的是写者代码,读者代码信号量处理与此类似)

void writers(){void *thread_ret;pthread_t write_thread[WR_THREAD_NUM];int res;int i=0;//create writer threadfor(i=0;i<WR_THREAD_NUM;i++){sem_init(&sem_W[i],0,0);//sem_initial(sem_W[i],0);res=pthread_create(&write_thread[i],NULL,writerThread,(void*)i);if(res!=0){perror("create writer thread fail!\n");exit(1);}else{printf("create writer thread success:%d\n",i);}}printf("All write thread created success!\n");/*printf("sleeping...\n");sleep(5000);printf("wake!\n");*/sem_post(&sem_W[0]);//begin writer thread//sem_p(sem_W[0]);for(i=0;i<WR_THREAD_NUM;i++){res=pthread_join(write_thread[i],&thread_ret);if(res!=0){perror("join error!\n");}else{printf("thread have been joined!(%d)\n\n\n\n",i);}//v handleif(i<WR_THREAD_NUM){sem_post(&sem_W[i+1]);}//sem_p(sem_W[i]);}//destroy semfor(i=0;i<WR_THREAD_NUM;i++){sem_destroy(&sem_W[i]);//sem_del(sem_W[i]);}}

(6)流程图:

 

总结

在本次课程设计中,学习了线程间的协调一致问题(使用信号量解决),进程间文件操作的协调一致(使用文件锁解决),以及基本文件的读写操作。其中在第一次时由于没有考虑到文件锁的运用问题,故采用了自定义文件描述符的方法,但在此中发现无法协调进程间操作文件的协调问题,而后采用了系统API(文件锁)较好的解决了此课题。在操作过程中为了体现线程间的信号量运用问题,采用了一个进程下创建多个线程的方法,同时为了使运行过程便于观察引入了随机时间挂起线程的方法。

 

源码资源

因为最近有许多小伙伴问起源码,这里将完整源码打包如下供参考:

https://download.csdn.net/download/qq_34901049/12538334

 


http://chatgpt.dhexx.cn/article/Iqnu2UPO.shtml

相关文章

写优先的读者写者问题(Java实现)

该题系吉林大学19级软件学院操作系统课设题之一 先输入初始时的写者读者情况&#xff0c;优先级顺序做了随机处理 代码如下 GUI&#xff1a; import javax.swing.*; import javax.swing.border.Border; import javax.swing.text.BadLocationException; import javax.swing.tex…

操作系统读者写者问题代码实现

问题分析&#xff1a; 读者优先: 读者进程执行: 无其他读者写者, 直接执行有写者等, 但其他读者在读, 直接读有写者写, 等待写者进程执行: 无其他读写者, 直接执行有其他读写者, 等待 写者优先: 读者进程执行: 如果此时没有写者等待, 直接执行如果有写者等待, 那么等待写者…

读者写者问题详解 操作系统

2.16 读者写者问题 抽象解释 多个进程访问一个共享的数据区读者&#xff08;读进程&#xff09;只能读数据&#xff0c;写者&#xff08;写进程&#xff09;只能写数据适用于数据库、文件、内存、寄存器等数据区的访问模型如12306购票系统&#xff0c;由于用户量庞大和数据量…

同步机制—读者写者问题

【实验目的】 理解临界区和进程互斥的概念&#xff0c;掌握用信号量和PV操作实现进程互斥的方法。 【实验内容】 在windows或者linux环境下编写一个控制台应用程序&#xff0c;该程序运行时能创建N个线程&#xff0c;其中既有读者线程又有写者线程&#xff0c;它们按照事先设计…

操作系统——读者写者问题

一、问题描述 要求: 1、允许多个读者可以同时对文件执行读操作。 2、只允许一个写者往文件中写信息。 3、任一写者在完成写操作之前不允许其他读者或写者工作。 4、写者执行写操作前,应让已有的读者和写者全部退出。 二、问题分析 读者写者问题最核心的问题是如何处理…

【操作系统-进程】PV操作——读者写者问题

文章目录 读者写者问题万能模板万能模板 1——读进程优先万能模板 2——读写公平法万能模板 3——写进程优先 题目 1&#xff1a;南北过桥问题题目 2&#xff1a;录像厅问题题目 3&#xff1a;更衣问题 读者写者问题万能模板 读者写者问题&#xff0c;其本质就是连续多个同类进…

经典进程同步问题(三)——读者写者问题

目录 一、问题描述 二、解题思路 2.1 读者优先算法 2.2 写者优先算法 2.3 读写公平 三、源码实现 3.1 读者优先 3.2 写者优先 3.3 读写平等 一、问题描述 一个数据问价或记录可以被多个进程共享&#xff0c;我们把只读该文件的进程称为“读者进程”&#xff0c;其他进…

2. 堆与栈的区别

2. 堆与栈的区别 在理解这两个概念时&#xff0c;需要放到具体的场景下&#xff0c;因为不同场景下&#xff0c;堆与栈代表不同的含义。一般情况下&#xff0c;有两层含义&#xff1a; &#xff08;1&#xff09;程序内存布局场景下&#xff0c;堆与栈表示的是两种内存管理方式…

栈与堆的区别(内存分配与数据结构)

参考自https://blog.csdn.net/K346K346/article/details/80849966/ 堆&#xff08;Heap&#xff09;与栈&#xff08;Stack&#xff09;包含两层含义&#xff1a; 程序内存布局场景下的内存管理方式数据结构中的两种常见的数据结构 1. 程序内存分配中的堆与栈 1.1 栈介绍 …

C语言里栈和堆的区别整理

这里说的是C语言程序内存分配中的堆和栈。下面先谈谈C语言的内存管理&#xff1a; 可执行程序在存储时&#xff08;没有调到内存&#xff09;分为代码区&#xff08;text&#xff09;、数据区&#xff08;data&#xff09;和未初始化数据区&#xff08;bss&#xff09;3个部分。…

看懂堆与栈的区别与联系

<div class"simditor-body clearfix" style"height: auto; overflow: inherit;"><h2> <strong>  堆和栈概要</strong></h2>在计算机领域&#xff0c;堆栈是一个不容忽视的概念&#xff0c;堆栈是两种数据结构。堆栈都是一…

C语言:栈和堆的区别

c语言五大内存分区 栈区&#xff08;stack&#xff09;:存放函数形参和局部变量&#xff08;auto类型&#xff09;&#xff0c;由编译器自动分配和释放 堆区&#xff08;heap&#xff09;:该区由程序员申请后使用&#xff0c;需要手动释放否则会造成内存泄漏。如果程序员没有手…

什么是栈(Stack)?什么是堆(Heap)?栈和堆的区别是什么?

原参考地址&#xff1a;https://zhidao.baidu.com/question/36918441.html 栈&#xff1a;由操作系统自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量du的值等。其操作方式类似于数据结构中的栈&#xff1b; 堆&#xff1a; 一般由程序员分配释放&#xff0c…

堆和栈的概念和区别

在说堆和栈之前&#xff0c;我们先说一下JVM&#xff08;虚拟机&#xff09;内存的划分&#xff1a; Java程序在运行时都要开辟空间&#xff0c;任何软件在运行时都要在内存中开辟空间&#xff0c;Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域&#x…

堆与栈的区别详细总结

1、堆与栈的区别详细总结_Fighting的博客-CSDN博客_堆和栈的区别 2、堆和栈的区别 - 江雨牧 - 博客园 3、堆和栈的区别_内外皆秀的博客-CSDN博客_堆和栈的区别 4、一文读懂堆与栈的区别_恋喵大鲤鱼的博客-CSDN博客_堆和栈的区别 一般情况下&#xff0c;如果有人把堆栈合起来…

栈和堆的区别

栈和堆的区别 前面已经介绍过&#xff0c;栈是由编译器在需要时分配的&#xff0c;不需要时自动清除的变量存储区。里面的变量通常是局部变量、函数参数等。堆是由malloc()函数分配的内存块&#xff0c;内存释放由程序员手动控制&#xff0c;在C语言为free函数完成。栈和堆的主…

Struts常见面试题

Struts分为Struts1和Struts2&#xff0c;默认情况下指的是Struts2&#xff0c;Struts1除非特别说明。 1、Struts2 中的 # 和 % 分别是做什么的&#xff1f; &#xff08;1&#xff09;使用#获取 context 里面的数据 <s:iterator value “list” var”user”> <s:p…

关于Struts2的笔试题(一)

一. struts2框架中struts.xml配置文件,package标签的属性有那几个?各有什么功能? 1.name属性 作用:定义一个包的名称&#xff0c;它必须唯一。 2.namespace属性 作用:主要是与action标签的name属性联合使用来确定一个action 的访问路径 3.extends属性 作用:指定继承自哪个…

Struts2详述一(struts2基础及2个核心)

临近大学毕业了&#xff0c;在毕业之前做点大学学到的知识和总结。如有哪些方面存在错误还望大神见谅。 首先&#xff0c;这里想从SSH这三大框架说起。首选从最简单的Struts2说起。这一篇我将讲述struts2一些基础及2个核心&#xff08;Action和result&#xff09;,下篇我们将着…

【面试】【Struts2常见问题总结】【02】

【常见面试问题总结目录>>>】 031 struts2如何对指定的方法进行验证&#xff1f; 1.validate()方法会校验action中所有与execute方法签名相同的方法&#xff1b;   2.要校验指定的方法通过重写validateXxx()方法实现&#xff0c; validateXxx()只会校验action中方法…