操作系统上机作业

实验一

题干

用两个进程来模拟汽车司机与售票员之间的协同关系:一方面只有售票员把车门关好了司机才能关门,因此,售票员管好车门应通知司机开车;另一方面,只有当汽车已经停下,售票员才能开门上下客,故司机停车后应通知售票员。汽车当前正在始发站停车上客,试设必要的信号量并赋初值,写出它们的同步过程。

实验目的

通过使用信号量及有关的P、V操作,实现操作系统中一般的同步机制。

实验思路

整体框架:一名司机和一名售票员各自是一个线程;

两个信号量:S1—是否关车门可以发动公交车;S2—是否到站可以开车门;

司 机:控制着汽车的到站停车[V(S2)]+售票员关门后通知司机可以发车启动[P(S1)];

售票员:司机到站停车后通知售票员可以开车门[P(S1)]+乘客上车后关车门[V(S2)];

说明:为了简化输出,假设每次上下车的人数符合常识,故没有设置相应变量表示人数的变化和上下车的实际动作。

实验结果

通过实践反映出两个线程之间实现了同步

img

当只有司机进程的时候,司机到站后S1信号量没有被售票员进行V操作,只有一直等待:

img

当只有售票员进程的时候,售票员没有接到司机停车的信号(即S2信号没有置为1),只有一直等待到站:

img

源代码(Python3.6.2)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 导入和线程、时间有关的包
import threading
import time


s1 = 0
# 1:售票员通知司机可以开车,0:司机通知售票员不能开门
s2 = 0
# 1:司机通知售票员可以开门,0:售票员通知司机不能开车


class Driver(object):
	"""司机类"""
	# 司机执行的程序
	def drive(self):
		while True:
			self.v()
			time.sleep(1)
			self.p()
			time.sleep(1)

	# 申请信号量s1
	def p(self):
		global s1

		while s1 != 1:
			time.sleep(0.5)
		time.sleep(0.5)
		s1 -= 1
		print('{}  司 机-汽车启动!'.format(time.ctime()))

	# 释放信号量s2
	def v(self):
		global s2

		while s2 != 0:
			time.sleep(0.5)
		time.sleep(0.5)
		s2 += 1
		print('{}  司 机-到站!'.format(time.ctime()))


class Conductor(object):
	"""售票员类"""

	def sellTicket(self):
		while True:
			self.p()
			time.sleep(1)
			self.v()
			time.sleep(1)

	# 申请信号量s2
	def p(self):
		global s2

		while s2 != 1:
			time.sleep(0.5)
		time.sleep(0.5)
		s2 -= 1
		print('{}  售票员-开车门!'.format(time.ctime()))

	# 释放信号量s1
	def v(self):
		global s1

		while s1 != 0:
			time.sleep(0.5)
		time.sleep(0.5)
		s1 += 1
		print('{}  售票员-关车门!'.format(time.ctime()))


if __name__ == '__main__':
	# 实例化司机类
	driver = Driver()
	# 实例化售票员类
	conductor = Conductor()
	# 创建司机执行的线程
	t1 = threading.Thread(target=driver.drive)
	# 创建售票员执行的线程
	t2 = threading.Thread(target=conductor.sellTicket)
	# 线程启动
	t1.start()
	t2.start()

实验二

题干

固定分区法就是把内存区固定地划分为若干个大小不等的区域。系统对内存的管理和控制通过数据结构----分区说明表进行,分区说明表各分区号、分区大小、起始地址和是否是空闲区。内存的分配和释放、存储保护以及地址变换等都通过分区说明表进行。要求:模拟内存分区的分配与回收过程。

实验目的

固定分区管理方式的主存分配回收模拟系统的设计。

实验思路

  1. 初始化分区状态表,每个分区都包括唯一的序号(no)、分区大小(size)、起始地址(sa)、是否空闲的标志(flag)。
  2. 假设有若干个需要分配的内存(大小有random包随机生成),对每个需要分配空间的任务分配一个线程,完成查找一个可存放空间的工作、分区使用结束后释放的工作。
  3. 加入某一个或几个待分配的空间当前没有被分配,则将其所需空间加入到一个等待列表中等待下一次检查哪里可以分配,直到所有程序被分配且使用完释放后主程序结束。

实验结果

此为共5个所需分配的任务

img

源代码(Python3.6.2)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
# 导入和线程、时间、随机数有关的包
import threading
import time
import random


class Cumputer(object):
	"""docstring for Cumputer"""
	def __init__(self):
		# Partition status table--分区状态表
		self.tablelist = []
		# 包含要存放的分区的列表
		self.runlist = []
		# 包含暂时无法存放的分区的列表
		self.waitlist = []

	# 初始化分区状态表
	def inittablelist(self):
		# ordinary number--序号
		# 特别说明:假设第一块为系统所用分区,不可用于分配空间
		on = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		# 各个分区的大小
		size = [10, 20, 20, 20, 40, 40, 40, 100, 100, 200]
		# start address--分区起始地址
		sa = [0, 10, 30, 50, 70, 110, 150, 190, 290, 390]
		# 该分区是否可用的标志
		flag = [False, True, True, True, True, True, True, True, True, True, ]

		# 将每个分区的属性写成分区表动态表
		for i in on:
			temp_dic = {
				'on': i,
				'size': size[i],
				'sa': sa[i],
				'flag': flag[i],
			}
			self.tablelist.append(temp_dic)

	# 主程序
	def running(self):
		# 首先初始化分区状态表
		self.inittablelist()

		# 假设需要分配10个空间
		for i in range(5):
			# 创建对应线程
			self.runlist.append(threading.Thread(target=self.work, args=(random.randint(1, 20) * 10, )))
		# 每个进程开始执行
		for i in self.runlist:
			i.start()
		# 所有进程执行后才继续主线程
		for i in self.runlist:
			i.join()

		# 当等待分配列表里还有成员时一直循环
		while len(self.waitlist) != 0:
			# 清空运行列表
			self.runlist = []
			# 为等待列表里的成员创建线程和启动线程
			for i in range(len(self.waitlist)):
				self.runlist.append(threading.Thread(target=self.work, args=(self.waitlist[0],)))
				self.waitlist.pop(0)
			for i in self.runlist:
				i.start()
			for i in self.runlist:
				i.join()

	# 线程函数
	def work(self, given_size):
		# result存放查找的结果
		result = self.find_a_place(given_size)
		# 若找到一个可用的分区
		if result[0] == 1:
			print('{}  {}工作已分配--{}'.format(time.ctime(), given_size, self.tablelist[result[1]]))
		# 若没有找到则将所需空间加入到等待列表
		else:
			print('{}  {}错误!没有空间存放!'.format(time.ctime(), given_size))
			self.waitlist.append(given_size)
			return 0

		# 模拟占用分区的时间
		time.sleep(random.randint(2, 4))

		# 释放分区
		self.release_the_place(result[1])
		print('{}  {}空间已释放!'.format(time.ctime(), given_size))

	# 查找有没有课分配的分区
	def find_a_place(self, given_size):
		for i in self.tablelist:
			with threading.Lock():
				# 查找比所需分区大且可以被使用的分区
				if given_size <= i['size'] and i['flag']:
					# 更改标志表示已被使用
					i['flag'] = False
					# 成功则返回1和序号
					return [1, i['on']]
		# 失败则返回0和-1
		return [0, -1]

	# 释放已占用的分区
	def release_the_place(self, given_on):
		with threading.Lock():
			# 更改标志后该分区又可被使用
			self.tablelist[given_on]['flag'] = True
		return 1

if __name__ == '__main__':
	# 实例化计算机类并执行程序
	cumputer = Cumputer()
	cumputer.running()
updatedupdated2020-05-252020-05-25