进程

引子

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. 断点的处理器环境

四方面信息:
1. 进程标示符
2. 处理器状态
3. 进程调度信息
4. 进程控制信息

进程的阻塞(block原语)主动行为

  1. 请求系统服务。但由于某种原因,操作系统并不立即满足该进程的要求时。该进程只能转变为阻塞状态来等待。
  2. 启动某种操作。如果该进程必须在该操作完成后才能继续执行,则必须先使该进程阻塞。比如进程启动了某IO设备
  3. 新数据尚未到达。如a进程输入数据,b进程加工数据
  4. 无新工作可做。如发送进程,发送完已有数据,而又无新的发送请求,就将自己阻塞起来
    过程:
    PCB中的现行状态改为“阻塞”,PCB插入阻塞队列(如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞(等待)队列),调度程序进行重新调度。

进程的唤醒(wakeup原语)

当被阻塞的进程所期待的事件出现时,如io完成,则由有关的进程(如用完并释放了该IO的进程)调用wakeup原语。wakeup原语首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后将该PCB插入到就绪队列中。

进程的挂起(suspend原语)

用户请求将自己挂起,或父进程请求将自己的某个子进程挂起。

进程的激活(active原语)

将进程从外存调入内存,检测现行状态,静止就绪–>活动就绪,静止阻塞–>活动阻塞

进程同步

制约关系

  1. 间接制约:共享某种资源。a占打印机,b想要用打印机
  2. 直接制约:a通过单缓冲向b提供数据

临界资源

打印机等,应采用互斥方式共享。

原则

  1. 空闲让进
  2. 忙则等待
  3. 有限等待(防死等)
  4. 让权等待(进程不能进入自己的临界区时,应立即释放处理器,以免“忙等”)

信号量

整型信号量

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
信号量的应用
  1. 进程互斥
  2. 前趋关系
    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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值