进程间两种形式的制约关系
两种制约关系:资源共享、进程合作。有学过多线程编程的人应该知道两大模型:卖票模型和生产者消费者模型。资源共享也就是卖票模型,多人同时购买有限的票,多个单位同时使用同一个资源,这就是资源共享;
生产者消费者模型就是进程合作,生产者生产一个实体,消费者消费一个实体,其中消费者消费的前提是生产者已经生产出了实体,生产者生产的前提是消费者已经把实体消费掉。两个进程之间需要相互合作,这就是进程合作。
临界资源 --- 互斥访问
先来具体了解一下生产者消费者模型:
左侧是生产者进程,P1到Pl指生产者进程循环执行生产操作,同理C1到Cm;这里有个中间媒介Buffer,它是一个循环队列,它有多个存储单元组成。循环队列有in和out指针,开始时in和out指针指向同一单元;生产者生产出一个实体,in指针循环意义下加1,in指针表示的就是可以存储实体的位置;消费者消费一个实体,out指针循环意义下加1,表示消费掉一个实体,out指针表示的是可以消费的位置。
下面看一个伪代码实现的生产者消费者模型并分析代码执行:
这里面n表示的是Buffer的空间个数、do no-op就是什么都不做,counter表示剩余的个体数。这两个进程要同时进行,共享couter变量。这样执行会有什么问题呢?
计算机在执行程序的时候会将程序最终翻译为机器语言,counter++和counter--的机器语言是这样的:
// counter++
register1=counter;
register1=register1+1;
counter=register1;
// counter--
register2=counter;
register2=register2-1;
counter=register2;
假设两个进程同时执行了counter++和counter--这两句代码,那换到机器语言中,它的执行顺序就是不固定的。比如:
// 假设counter为5
register1=counter; (register1=5)
register1=register1+1; (register1=6)
register2=counter; (register2=5)
register2=register2-1; (register2=4)
counter=register1; (counter=6)
counter=register2; (counter=4)
// counter++、counter--的正确结果应该还是5,这里结果变成了4
看似counter++和counter--分开执行,实际并不是,并且这样的程序还会引起结果出现重大错误。解决办法就是把counter作为临界资源,对两个进程互斥访问。临界资源就是一次仅允许一个进程访问的资源。
临界区
临界区:每个进程中访问临界资源的那段代码。进程互斥:两进程不能同时进入访问同一临界资源的临界区。
为了避免上面的错误,我们要更改临界区代码的设计。在要进入临界区时,进行标志位判断,标志位显示临界区没有被访问,那么我们就可以进入临界区,并且把标志位设置为正在访问。执行完代码, 退出临界区的时候再将标志位恢复为未访问状态。
至此我们可以引出进程同步的概念,进程同步:某进程未获得合作进程发来消息之前该进程等待,消息到来之后方可继续执行的合作关系;同步机制:系统用来实现进程间同步与互斥的机构。
同步机制应遵循的规则
空闲让进、忙则等待、有限等待、让权等待。
空闲让进:临界区没有执行的进程,则允许进程进入临界区。
忙则等待:要执行临界区的进程因临界区无法访问而等待。
有限等待:要访问临界区的进程应在有限时间内完成,防止变成死锁。
让权等待:无法访问临界区的等待时间一道,确定无法访问,该进程会立刻释放处理机,让出资源。
用白话说就是:屋里没人的时候就进去,有人就等一会,最多等10分钟,10分钟后屋里还有人就不等了,直接走人。