引子
fork
os中的fork或python中的p.start用于从父进程中分叉出一个子进程。
p.join()是指什么呢?
当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在kernel里留下自己的退出信息(exit code,如果顺利运行,为0;如果有错误或异常状况,为>0的整数)。在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用wait系统调用。这个wait函数能从kernel中取出子进程的退出信息,并清空该信息在kernel中所占据的空间。
python里的join就是wait系统调用的封装
from multiprocessing import Process
import os
def run_proc(name):
print 'Run child process %s (%s)..' % (name, os.getpid())
if __name__ == '__main__':
print 'Parent process %s.' % os.getpid()
p = Process( target = run_proc , args=("test",) )
print 'process will start.'
p.start()
p.join() // join在干嘛??
print 'process end.'
进程池
from multiprocessing import Pool
import os,time,random
def long_time_task(name):
print 'run task %s (%s) ...' % (name,os.getpid())
start = time.time()
time.sleep(random.random() * 3 ) // sleep是什么状态?挂起?好像还在执行状态?。。。
end = time.time()
print 'task %s runs %0.2f seconds.' % (name, (end-start))
if __name__ == '__main__':
print 'parent process %s.' % os.getpid()
p = Pool()
for i in range(7):
p.apply_async(long_time_task, args=(i,) )
print 'waiting for all subprocesses done..'
p.close()
p.join()
print 'all subprocesses done.'
os中的概念
状态
就绪,执行,阻塞
|就绪| –进程调度–> |执行| –io请求–> |阻塞| –io完成–> |就绪|
|执行| –时间片完–> |就绪|
挂起
原因:
1. 终端用户的请求
2. 父进程请求
3. 系统调节负载
4. 操作系统检查运行资源、记账
创建、终止
PCB
- 现行状态、优先级
- 处理器状态信息
- 程序和数据的内存地址
- 断点的处理器环境
四方面信息:
1. 进程标示符
2. 处理器状态
3. 进程调度信息
4. 进程控制信息
进程的阻塞(block原语)主动行为
- 请求系统服务。但由于某种原因,操作系统并不立即满足该进程的要求时。该进程只能转变为阻塞状态来等待。
- 启动某种操作。如果该进程必须在该操作完成后才能继续执行,则必须先使该进程阻塞。比如进程启动了某IO设备
- 新数据尚未到达。如a进程输入数据,b进程加工数据
- 无新工作可做。如发送进程,发送完已有数据,而又无新的发送请求,就将自己阻塞起来
过程:
PCB中的现行状态改为“阻塞”,PCB插入阻塞队列(如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞(等待)队列),调度程序进行重新调度。
进程的唤醒(wakeup原语)
当被阻塞的进程所期待的事件出现时,如io完成,则由有关的进程(如用完并释放了该IO的进程)调用wakeup原语。wakeup原语首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后将该PCB插入到就绪队列中。
进程的挂起(suspend原语)
用户请求将自己挂起,或父进程请求将自己的某个子进程挂起。
进程的激活(active原语)
将进程从外存调入内存,检测现行状态,静止就绪–>活动就绪,静止阻塞–>活动阻塞
进程同步
制约关系
- 间接制约:共享某种资源。a占打印机,b想要用打印机
- 直接制约:a通过单缓冲向b提供数据
临界资源
打印机等,应采用互斥方式共享。
原则
- 空闲让进
- 忙则等待
- 有限等待(防死等)
- 让权等待(进程不能进入自己的临界区时,应立即释放处理器,以免“忙等”)
信号量
整型信号量
p(wait) : 获取信号量,并减一。
v(signal):释放信号量,并加一。
均不可中断
wait(S):
while S <= 0 do no-op
S = S-1
signal(S):
S = S+1
记录型信号量
不断检测信号量会“忙等”,所以有了“记录型信号量”
type semaphore = record
value: integer
L: list of process
end
procedure wait(S)
var S: semaphore
begin
S.value = S.value - 1
if S.value < 0 then block(S.L) //自我阻塞
end
procedure signal(S)
var S: semaphore
begin
S.value = S.value + 1;
if S.value <= 0 then
wakeup(S.L) //将链表中的第一个等待进程唤醒
end
and型信号量
进程a和b都要求访问共享数据d和e,必须同时得到资源才能执行。这种情况会引发“死锁”
解决方法是要么全分配,要么一个也不分配。
Swait(S1,S2,...Sn)
if Si >=1 and ... and Sn>=1 then
for i = 1 to n do
Si = Si - 1
endfor
else
place the process in the waiting queue associated with the first Si found with Si<1
set the program count of this processs to the beginning of Swait operation
endif
Ssignal(S1,S2...Sn)
for i=1 to n do
Si = Si + 1
remove all hte process waiting in the queue associated with Si into the ready queue.
//对应:Swait失败进入Si的阻塞(等待)队列
endfor
信号量集
wait(S), signal(S)每次仅能加一减一,当一次需要N个某类资源时,较为低效。此外,当资源数量低于某下限时,便不予以分配,因而每次分配前都要测试数量。可抽象:S为信号量,d为需求值,t为下限
Swait(S1,t1,d1, ... Sn,tn,dn)
if Si>=ti and ... and Sn>=tn then
for i=1 to n do
Si = Si-di
endfor
else
place the executing process in the waiting queue of the first Si with Si<ti
set its program counter to the beginning of the Swait opertion
endif
Ssignal(S1,d1,... Sn,dn)
for i=1 to n do
Si = Si + di
remove all the process waiting in queue asscociated with Si into the ready queue
endfor
信号量的应用
- 进程互斥
- 前趋关系
p1中有语句s1, p2中有语句s2. signal(S)放在s1后,wait(S)放在s2前即可。
管程
wait, signal使得大量的同步操作分散在各个进程中。这给系统的管理带来了麻烦。
管程是新的同步工具。它相当于围墙,把共享变量和对它进行操作的若干过程为了起来。所有进程要访问临街资源时,必须经过管程才能进入。而管程每次只允许一个进程进入管程,从而实现了进程互斥。
抽象资源–>数据结构
共享资源操作–>一组过程
利用管程解决生产者-消费者问题
type producer = consumer = monitor
var in, out, count: integer
buffer: array[0,1,...n-1] of item
notfull, notempty: condition
procedure entry put(item):
begin
if count>=n then notfull.wait
buffer(in) = nextp
in = (in+1) mod n
count += 1
if notempty.queue then notempty.signal
end
procedure entry get(item)
begin
if count<=0 then notempty.wait
nextc = buffer(out)
out = (out+1) mod n
count = count-1
if notfull.queue then notfull.signal
end
begin
in = out = 0
count = 0
end
应用
记录型信号量解生产者消费者问题
var mutex , empty , full : semaphore = 1,n,0
buffer: array[0,..., n-1] of item
in, out : interger = 0,0
begin
parbegin
procedure: begin
repeat
produce an item nextp
wait(empty) // 生产n个后为零。初始n, 表示缓存 可写数量
wait(mutex)
buffer(in) = nextp
in = in + 1 mod n
signal(mutex)
signal(full) //初始为0, 表示缓存 可读数量
end
consumer: begin
repeat
wait(full) // 可读减一
wait(mutex)
nextc = buffer(out)
out = out+1 mod n
signal(mutex)
signal(empty) // 可写加一
cosume the item in nextc
end
parend
end
and信号量解生产者-消费者问题
var mutex, empty , full = 1,n,0
buffer: array[0,...,n-1] of item
in, out : interger = 0,0
begin
parbegin
producer: begin
repeat:
produce an item in nextp
Swait( empty , mutex )
buffer(in) = nextp
in = (in + 1) mod n
Ssignal( full , mutex )
end
end
consumer: begin
repeat:
Swait( full , mutex )
nextc = buffer(out)
out = (out+1) mod n
Ssignal( empty , mutex )
consume nextc //why here 而不是 cs 里面?
end
end
parend
end

5034

被折叠的 条评论
为什么被折叠?



