Lec12练习

1(不用回答)理解 孤儿进程和僵死进程的含义
http://www.cnblogs.com/xiehongfeng100/p/4619913.html
http://www.cnblogs.com/Anker/p/3271773.html
https://piazza.com/class/i5j09fnsl7k5x0?cid=753

孤儿进程:一个父进程退出、但其仍在运行的孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占用的资源)的进程。

5 请仔细阅读https://chyyuu.gitbooks.io/os_course_exercises/content/all/05-2-spoc-discussion.html. 中的小组思考题

设计一个简化的进程管理子系统,可以管理并调度如下简化进程.给出了参考代码(https://github.com/chyyuu/ucore_lab/blob/master/related_info/lab5/process-cpuio-homework.py),请理解代码,并完成"YOUR CODE”部分的内容.

根据注释及gitbook中的提示完成实验即可,需要注意的是切换进程的时刻有:进程结束或进程发出yield请求

以及IO的时间设置问题,由输出的提示可知:
System will switch when the current process is FINISHED or ISSUES AN YIELD or IO
After IOs, the process issuing the IO will run LATER (when it is its turn)

因此,io完成时间应该是 clock_tick + self.io_length + 2,即需要两个切换时间

1
2
# 设置IO完成时间
self.io_finish_times[self.curr_proc].append(clock_tick + self.io_length + 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#! /usr/bin/env python
# coding:utf8
import sys
from optparse import OptionParser
import random

# process switch behavior
SCHED_SWITCH_ON_IO = 'SWITCH_ON_IO'

# io finished behavior
IO_RUN_LATER = 'IO_RUN_LATER'

# process states
STATE_RUNNING = 'RUNNING'
STATE_READY = 'READY'
STATE_DONE = 'DONE'
STATE_WAIT = 'WAITING'

# members of process structure
PROC_CODE = 'code_'
PROC_PC = 'pc_'
PROC_ID = 'pid_'
PROC_STATE = 'proc_state_'

# things a process can do
DO_COMPUTE = 'cpu'
DO_YIELD = 'yld'
DO_IO = 'io'


class scheduler:
def __init__(self, process_switch_behavior, io_done_behavior, io_length):
# keep set of instructions for each of the processes
self.proc_info = {}
self.process_switch_behavior = process_switch_behavior
self.io_done_behavior = io_done_behavior
self.io_length = io_length
return

def new_process(self):
proc_id = len(self.proc_info)
self.proc_info[proc_id] = {}
self.proc_info[proc_id][PROC_PC] = 0
self.proc_info[proc_id][PROC_ID] = proc_id
self.proc_info[proc_id][PROC_CODE] = []
self.proc_info[proc_id][PROC_STATE] = STATE_READY
return proc_id

def load(self, program_description):
proc_id = self.new_process()
tmp = program_description.split(':')
if len(tmp) != 3:
print 'Bad description (%s): Must be number <x:y:z>'
print ' where X is the number of instructions'
print ' and Y is the percent change that an instruction is YIELD'
print ' and Z is the percent change that an instruction is IO'
exit(1)

num_instructions, chance_yield, chance_io = int(tmp[0]), float(
tmp[1]) / 100.0, float(tmp[2]) / 100.0
assert (chance_yield + chance_io < 1)

# print "proc %d, num_instr %d, change_cpu %f" % (proc_id,num_instructions, chance_cpu)
for i in range(num_instructions):
randnum = random.random();
if randnum < (1.0 - chance_yield - chance_io):
self.proc_info[proc_id][PROC_CODE].append(DO_COMPUTE)
elif randnum >= (1.0 - chance_yield - chance_io) and randnum < (
1.0 - chance_io):
self.proc_info[proc_id][PROC_CODE].append(DO_YIELD)
else:
self.proc_info[proc_id][PROC_CODE].append(DO_IO)
# print "proc %d, instr idx %d, instr cxt %s" % (proc_id, i, self.proc_info[proc_id][PROC_CODE][i])
return

# change to WAIT STATE, the current proc's state should be expected
def move_to_wait(self, expected):
assert (self.proc_info[self.curr_proc][PROC_STATE] == expected)
self.proc_info[self.curr_proc][PROC_STATE] = STATE_WAIT
return

# change to READY STATE, the current proc's state should be expected
# if pid==-1, then pid=self.curr_proc
def move_to_ready(self, expected, pid=-1):
# YOUR CODE
if pid is -1:
pid = self.curr_proc
assert (self.proc_info[pid][PROC_STATE] == expected)
self.proc_info[pid][PROC_STATE] = STATE_READY
return

# change to RUNNING STATE, the current proc's state should be expected
def move_to_running(self, expected):
# YOUR CODE
assert (self.proc_info[self.curr_proc][PROC_STATE] == expected)
self.proc_info[self.curr_proc][PROC_STATE] = STATE_RUNNING
return

# change to DONE STATE, the current proc's state should be expected
def move_to_done(self, expected):
# YOUR CODE
assert (self.proc_info[self.curr_proc][PROC_STATE] == expected)
self.proc_info[self.curr_proc][PROC_STATE] = STATE_DONE
return

# choose next proc using FIFO/FCFS scheduling, If pid==-1, then pid=self.curr_proc
def next_proc(self, pid=-1):
# YOUR CODE
"""
使用FIFO/FCFS:先来先服务, 只有进程done, yield, io时才会执行切换
先查找位于proc_info队列的curr_proc元素(当前进程)之后的进程(curr_proc+1..end)是否处于READY态,
再查找位于proc_info队列的curr_proc元素(当前进程)之前的进程(begin..curr_proc-1)是否处于READY态
如都没有,继续执行curr_proc直到结束
"""
if pid == -1:
pid = self.curr_proc
# 使用FIFO/FCFS(先到先服务)调度算法选择下一个进程
for i in xrange(self.curr_proc + 1, len(self.proc_info)):
if self.proc_info[i][PROC_STATE] == STATE_READY:
self.curr_proc = i
self.move_to_running(STATE_READY)
return
# break

for i in xrange(0, self.curr_proc):
if self.proc_info[i][PROC_STATE] == STATE_READY:
self.curr_proc = i
self.move_to_running(STATE_READY)
return
# break

# 进程切换
if self.proc_info[self.curr_proc][PROC_STATE] == STATE_READY:
self.move_to_running(STATE_READY)
return

def get_num_processes(self):
return len(self.proc_info)

def get_num_instructions(self, pid):
return len(self.proc_info[pid][PROC_CODE])

def get_instruction(self, pid, index):
return self.proc_info[pid][PROC_CODE][index]

def get_num_active(self):
num_active = 0
for pid in range(len(self.proc_info)):
if self.proc_info[pid][PROC_STATE] != STATE_DONE:
num_active += 1
return num_active

def get_num_runnable(self):
num_active = 0
for pid in range(len(self.proc_info)):
if self.proc_info[pid][PROC_STATE] == STATE_READY or \
self.proc_info[pid][PROC_STATE] == STATE_RUNNING:
num_active += 1
return num_active

def get_ios_in_flight(self, current_time):
num_in_flight = 0
for pid in range(len(self.proc_info)):
for t in self.io_finish_times[pid]:
if t > current_time:
num_in_flight += 1
return num_in_flight

def space(self, num_columns):
for i in range(num_columns):
print '%10s' % ' ',

def check_if_done(self):
if len(self.proc_info[self.curr_proc][PROC_CODE]) == 0:
if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING:
self.move_to_done(STATE_RUNNING)
self.next_proc()
return

def run(self):
clock_tick = 0

if len(self.proc_info) == 0:
return

# track outstanding IOs, per process
self.io_finish_times = {}
for pid in range(len(self.proc_info)):
self.io_finish_times[pid] = []

# make first one active
self.curr_proc = 0
self.move_to_running(STATE_READY)

# OUTPUT: heade`[rs for each column
print '%s' % 'Time',
for pid in range(len(self.proc_info)):
print '%10s' % ('PID:%2d' % (pid)),
print '%10s' % 'CPU',
print '%10s' % 'IOs',
print ''

# init statistics
io_busy = 0
cpu_busy = 0

while self.get_num_active() > 0:
clock_tick += 1

# check for io finish
io_done = False
for pid in range(len(self.proc_info)):
if clock_tick in self.io_finish_times[pid]:
# if IO finished, the should do something for related process
# YOUR CODE
# IO完成,将pid进程转换为Ready状态
self.move_to_ready(STATE_WAIT, pid)
if self.proc_info[self.curr_proc][
PROC_STATE] != STATE_RUNNING:
self.next_proc();
io_done = True
# pass #YOU should delete this

# if current proc is RUNNING and has an instruction, execute it
instruction_to_execute = ''
if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING and \
len(self.proc_info[self.curr_proc][PROC_CODE]) > 0:
# pop a instruction from proc_info[self.curr_proc][PROC_CODE]to instruction_to_execute
# YOUR CODE
instruction_to_execute = self.proc_info[self.curr_proc][
PROC_CODE].pop(0)
# pass #YOU should delete this

# OUTPUT: print what everyone is up to
if io_done:
print '%3d*' % clock_tick,
else:
print '%3d ' % clock_tick,
for pid in range(len(self.proc_info)):
if pid == self.curr_proc and instruction_to_execute != '':
print '%10s' % ('RUN:' + instruction_to_execute),
else:
print '%10s' % (self.proc_info[pid][PROC_STATE]),
if instruction_to_execute == '':
print '%10s' % ' ',
else:
print '%10s' % 1,
num_outstanding = self.get_ios_in_flight(clock_tick)
if num_outstanding > 0:
print '%10s' % str(num_outstanding),
io_busy += 1
else:
print '%10s' % ' ',
print ''

# if this is an YIELD instruction, switch to ready state
# and add an io completion in the future
if instruction_to_execute == DO_YIELD:
# YOUR CODE
# 发出YIELD请求,放弃使用CPU, 进程切换
self.move_to_ready(STATE_RUNNING)
self.next_proc()
pass # YOU should delete this
# if this is an IO instruction, switch to waiting state
# and add an io completion in the future
elif instruction_to_execute == DO_IO:
# YOUR CODE
# 发出I/O操作请求,放弃使用CPU
self.move_to_wait(STATE_RUNNING)
# 设置IO完成时间
self.io_finish_times[self.curr_proc].append(
clock_tick + self.io_length + 2)
# 切换进程
self.next_proc()
pass # YOU should delete this
else:
cpu_busy += 1

# ENDCASE: check if currently running thing is out of instructions
self.check_if_done()
return (cpu_busy, io_busy, clock_tick)


#
# PARSE ARGUMENTS
#

parser = OptionParser()
parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
parser.add_option('-l', '--processlist', default='', help='a comma-separated list of processes to run, in the form X1:Y1:Z1,X2:Y2:Z2,... where X is the number of instructions that process should run, and Y/Z the chances (from 0 to 100) issue an YIELD/IO', action='store', type='string', dest='process_list')
parser.add_option('-L', '--iolength', default=3, help='how long an IO takes', action='store', type='int', dest='io_length')
parser.add_option('-p', '--printstats', help='print statistics at end; only useful with -c flag (otherwise stats are not printed)', action='store_true', default=False, dest='print_stats')
(options, args) = parser.parse_args()

random.seed(options.seed)

process_switch_behavior = SCHED_SWITCH_ON_IO
io_done_behavior = IO_RUN_LATER
io_length = options.io_length

s = scheduler(process_switch_behavior, io_done_behavior, io_length)

# example process description (10:100,10:100)
for p in options.process_list.split(','):
s.load(p)

print 'Produce a trace of what would happen when you run these processes:'
for pid in range(s.get_num_processes()):
print 'Process %d' % pid
for inst in range(s.get_num_instructions(pid)):
print ' %s' % s.get_instruction(pid, inst)
print ''
print 'Important behaviors:'
print ' System will switch when',
if process_switch_behavior == SCHED_SWITCH_ON_IO:
print 'the current process is FINISHED or ISSUES AN YIELD or IO'
else:
print 'error in sched switch on iobehavior'
exit(-1)
print ' After IOs, the process issuing the IO will',
if io_done_behavior == IO_RUN_LATER:
print 'run LATER (when it is its turn)'
else:
print 'error in IO done behavior'
exit(-1)
print ''

(cpu_busy, io_busy, clock_tick) = s.run()

print ''
print 'Stats: Total Time %d' % clock_tick
print 'Stats: CPU Busy %d (%.2f%%)' % (
cpu_busy, 100.0 * float(cpu_busy) / clock_tick)
print 'Stats: IO Busy %d (%.2f%%)' % (
io_busy, 100.0 * float(io_busy) / clock_tick)
print ''
打赏