【SCAU操作系统】实验一进程同步与互斥:读者-写者问题python源代码及实验报告参考

实 验 题 目    进程同步与互斥:读者-写者问题
摘 要    本次实验实现多线程编程和信号量控制,实现了读者-写者问题的解决方案,并通过多线程模拟了多个读者和写者并发访问共享资源的过程。代码的主要逻辑:读取输入数据,初始化信号量和全局变量,启动主线程,创建并启动线程,模拟读者写者行为,并发执行和输出。

一、需求分析

创建一个控制台进程,此进程包含 n 个线程。用这 n 个线程来表示 n个读者或写者。每个线程按相应测试数据文件的要求进行读写操作。要实现写-写互斥,读-写互斥,读-读允许。如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。但任何写者必须等到没有读者时才能开始写操作。

运行结果要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。

二、概要设计

  • 系统概述

本系统是一个多线程模拟程序,旨在实现读者-写者问题的解决方案。通过创建多个线程来模拟读者和写者对共享资源的并发访问,利用信号量机制控制对共享资源的访问权限,确保读者和写者之间的正确互斥和同步。

  • 模块
  1. 输入模块:负责从指定的文本文件中读取数据,解析出读者和写者的线程编号、操作类型、开始时间和持续时间,并将这些数据存储到相应的列表中。
  2. 线程创建与启动模块:根据输入模块提供的数据,为每个读者或写者创建一个线程,并设置相应的参数。然后启动这些线程,让它们并发执行。
  3. 读者模块:模拟读者的行为。读者线程在启动后会等待一段时间,然后尝试获取读取权限。如果当前没有其他读者正在读取,读者会获取写者互斥信号量Wmutex,确保写者不会进行写操作。接着,读者会更新读者计数Rcount,并开始读取操作。读取完成后,读者会释放写者互斥信号量,并更新读者计数。
  4. 写者模块:模拟写者的行为。写者线程在启动后会等待一段时间,然后尝试获取写权限。写者会获取写者互斥信号量Wmutex,确保独占写权限。然后,写者进行写操作。写操作完成后,写者会释放写者互斥信号量。
  5. 输出模块:负责在关键的时间点打印出线程的执行状态,包括线程编号、操作类型、开始时间和持续时间等信息。通过输出模块,可以观察多线程的执行过程和资源访问情况。
  • 数据结构
  1. idx:存储每个线程的编号。
  2. rwlist:存储每个线程的操作类型,包括读者和写者
  3. start_time:存储每个线程开始等待的时间。
  4. continue_time:存储每个线程的操作持续时间。
  5. Semaphore:使用两个信号量Wmutex和Rmutex来控制对共享资源的访问。Wmutex用于保护写操作,确保同一时间只有一个写者可以访问共享资源;Rmutex用于控制读者的并发访问。
  6. Rcount:用于记录当前并发读者的数量,实现读者之间的互斥和同步。

三、详细设计

  • 系统初始化:初始化信号量Wmutex和Rmutex为1,初始时没有线程在执行写操作或者等待读取。初始化全局变量Rcount为0,表示当前没有读者正在读取。
  • 输入模块:打开input.txt,逐行读取解析数据,提取线程编号、操作类型、开始时间和持续时间,并将数据存储到idx、rwlist、start_time和continue_time列表中,最后关闭文本文件。遍历rwlist列表,根据每个元素的操作类型创建相应的线程。对于读者线程,将线程编号、持续时间、全局开始时间以及等待开始时间作为参数传递给reader函数。对于写者线程,同样将线程编号、持续时间、全局开始时间以及等待开始时间作为参数传递给writer函数。使用threading.Thread类创建线程对象,并调用其start方法启动线程。
  • 读者模块:读者线程启动后,首先根据等待开始时间进行延时,模拟线程等待的过程,延时结束后,读者尝试获取Rmutex信号量,以确保在修改Rcount时的线程安全获取到Rmutex后,读者检查Rcount是否为0,如果是,则获取Wmutex信号量,以确保写者不会进行写操作,读者增加Rcount的值,表示有一个新的读者开始读取。释放Rmutex信号量,允许其他读者进入。读者开始执行读取操作,模拟读取过程。读取操作完成后,读者再次获取Rmutex信号量,准备退出。减少Rcount的值,表示有一个读者完成读取。如果Rcount变为0,表示所有读者都已完成读取,释放Wmutex信号量,允许写者进行写操作。释放Rmutex信号量,读者线程结束。
  • 写者模块:写者线程启动后,根据等待开始时间进行延时。延时结束后,写者尝试获取Wmutex信号量,以确保独占写权限,如果成功获取到Wmutex信号量,写者开始执行写操作,模拟写过程。写操作完成后,写者释放Wmutex信号量,允许其他读者或写者获取写权限,最后写者线程结束。
  • 输出模块:在相关时间点,通过打印语句输出线程的执行状态。输出内容包括线程编号、操作类型、当前时间以及持续时间等信息

四、调试分析

  1. 输出检查:查看程序输出的线程状态信息,每个线程都按照预期的时间点和顺序执行。
  2. 时间分析:分析线程的执行时间,不存在不必要的等待或延迟。
  3. 信号量状态分析:检查信号量的获取和释放情况,信号量的状态与线程的行为一致。
  4. 逻辑检查:代码逻辑符合读者-写者问题的要求,读者和写者的行为符合预期。
  5. 语法检查:代码中没有语法错误
  6. 变量参数检查:所有变量和参数都已正确初始化

五、用户使用说明

  1. 运行环境(操作系统:Windows;Python 版本:Python 3.x 版本;依赖库: Python 标准库)
  2. 准备输入文件input.txt

   

1 R 3 5

2 R 4 5

3 W 5 2

4 R 10 3

5 W 11 3

6 R 13 4

      3.运行

      4.结果输出

六、测试与运行结果

源代码:

import time
import threading
from threading import Semaphore

Wmutex = Semaphore(1)
Rmutex = Semaphore(1)
Rcount = 0

def reader(i,sleept,start,start_sleep):
    time.sleep(start_sleep)
    print('时间点  '+str(int(time.strftime('%S'))-start)+'  reader  '+str(i)+'  waiting to read\n', end='')
    Rmutex.acquire()
    global Rcount
    if Rcount == 0:
        Wmutex.acquire()
    Rcount += 1
    Rmutex.release()
    print('时间点  '+str(int(time.strftime('%S'))-start)+'  reader  '+str(i)+'  reading\n', end='')
    time.sleep(sleept)
    print('时间点  '+str(int(time.strftime('%S'))-start)+'  reader  '+str(i)+'  finish reading\n', end='')
    Rmutex.acquire()
    Rcount -= 1
    if Rcount == 0:
        Wmutex.release()
    Rmutex.release()

def writer(i,sleept,start,start_sleep):
    time.sleep(start_sleep)
    now = int(time.strftime('%S'))
    print('时间点  '+str(int(time.strftime('%S'))-start)+'  writer  '+str(i)+'  waiting to write\n', end='')
    Wmutex.acquire()
    print('时间点  '+str(int(time.strftime('%S'))-start)+'  writer  '+str(i)+'  writing\n', end='')
    time.sleep(sleept)
    print('时间点  '+str(int(time.strftime('%S'))-start)+'  writer  '+str(i)+'  finish writing\n', end='')
    Wmutex.release()


if __name__ == '__main__':
    idx = []
    rwlist = []
    start_time = []
    continue_time = []
    with open(r'C:\Users\JH\Desktop\input.txt','r',encoding='utf-8')  as f:
        data = f.readlines()
        for x in data:
            x = x.split()
            idx.append(int(x[0]))
            rwlist.append(x[1])
            start_time.append(int(x[2]))
            continue_time.append(int(x[3]))
    start = int(time.strftime('%S'))
    print('时间点  '+str(start-start)+'  所有线程开始启动\n', end='')
    for i in range(len(rwlist)):
        print('时间点  '+str(int(time.strftime('%S'))-start)+'  线程  '+str(idx[i])+'  set up\n', end='')
        if rwlist[i] == 'R':
            t = threading.Thread(target=reader, args=(idx[i],continue_time[i],start,start_time[i]))
            t.start()
        else:
            t = threading.Thread(target=writer, args=(idx[i],continue_time[i],start,start_time[i]))
            t.start()

  • 40
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SCAU综合实验课程中的文件操作与字符处理是一门非常重要的课程,它教授了如何使用计算机来操作文件以及对文件中的字符进行处理。 文件操作是指使用计算机来创建、打开、读取、写入、修改和关闭文件的过程。在实验中,我们学习了如何使用C++编程语言来实现这些文件操作。通过实践,我们可以掌握文件的基本操作,比如创建文件、打开已存在的文件、从文件中读取数据、向文件中写入数据和关闭文件等等。这些操作对于日常的文件处理工作非常有用。 字符处理是指对文件中的字符进行操作和处理的过程。我们学习了如何使用C++语言中的字符串类和字符数组来对字符进行处理。通过实验,我们可以掌握字符串的创建、拼接、截取、替换和转换等操作。这些操作可以帮助我们更好地处理文件中的文本数据,比如查找特定的字符、计算字符串的长度、在字符串中查找子字符串等等。 此外,我们还学习了一些常见的文件操作和字符处理的应用,比如统计一个文件中的字符数、单词数和行数,将一个文件中的大写字母转换为小写字母,将一个文件中的所有空格替换为换行符等等。这些应用可以帮助我们更好地理解文件操作和字符处理的实际应用场景,并提高我们的实际操作能力。 综上所述,SCAU综合实验中的文件操作与字符处理课程是非常实用和重要的一门课程,它教授了我们使用计算机来操作文件和处理字符的技能和知识。通过学习这门课程,我们可以提高我们的实际操作能力,为以后的工作做好准备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值