操作系统学习(十)
操作系统学习(十)
目录:
同步的基本概念
- 同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。
- 也就是相互制约的关系(共享资源)
临界资源和临界区
- 临界资源:
一段时间内只允许一进程访问的资源
- 临界区
程序中涉及到临界资源的代码段
- 准则
- 空闲让进
- 忙则等待
- 有限等待
- 让权等待
利用软件实现互斥
- 两个标志位
- 一个指针
利用硬件实现
- 加锁 -> 互斥锁
信号量机制
- 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。
- 信号量机制是一种卓有成效的进程互斥同步工具。这里只介绍记录型信号量机制,它可以有效的解决CPU“忙等”的问题,实现互斥。
物理含义:
- 正:资源的数量
- 负:阻塞进程的个数
整型信号量
把整型信号量定义为一个表示资源数目的整型量S,除初始化外,仅能通过两个标准的原子操作
wait(S)
和signal(S)
来访问。
记录型信号量
记录型信号量机制采取了“让权等待”策略,是一种不存在“忙等”现象的进程同步机制。记录型信号量时由于它采用了记录型数据结果而得名的。在信号量机制中,除了需要一个用于代表资源数目数的整型变量
value
外,还需要一个进程链表指针L
用于链接所有等待的进程。
信号量的应用
- 实现互斥:
- 信号量初值为1
- pv 成对出现
- 紧邻临界区
- 物理意义:
> 0 空闲个数
< 0 等待进程数
= 0 无等待进程并且无空闲个数
经典同步问题:
生产者消费者
问题描述:
一组生产者进程和一组消费者进程共享一个初始为空、大小为n的缓冲区,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息。
大致代码:
n个缓冲区,每个缓冲区可存一个数据项。信号量mutex提供缓冲池访问的互斥请求,并初始化为1.信号量empty和full分别用于表示空的和满的缓冲区数量。信号量empty初始化为n,信号量full初始化为0
生产者producer
do{
...
produce an item in next_produced
wait(empty);
wait(mutex);
...
add next_produced to the buffer
signal(mutex);
signal(full);
}while(true);
消费者consumer
do{
wait(full);
wait(mutex);
...
remove an item from buffer to next_consumed
...
signal(mutex);
signal(empty);
...
consume the item in next consumed
}while(true);
读者写者
问题描述:
有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出。
大致代码:
描述:
信号量mutex和rw_mutex初始化为1;read_count初始化为0.信号量rw_mutex为读者和写者进程所共用。信号量mutex用于确保在更新变量read_count时的互斥。变量read_count用于跟踪多少进程正在读对象。信号量rw_mutex供写者作为互斥信号量。他也为第一个进入临界区和最后一个离开临界区的读者所使用,而不为其他读者所使用
提供读写锁。
写者:
do{
wait(rw_mutex);
...
writing is performed
...
signal(rw_mutex);)
}while(true);
读者:
do{
wait(mutex);
read_count++;
if(read_count==1)
wait(rw_mutex);
signal(mutex);
...
reading is performed
...
wait(mutex);
read_count--;
if(read_count==0)
signal(rw_mutex);
signal(mutex);
}while(true);
哲学家就餐
问题描述:
假设有五个哲学家他们的生活只是吃饭和思考。这些哲学家共用一个圆桌,每位都有一把椅子。在桌子中间有一碗米饭,在桌子上放着5根筷子。当1位哲学家思考时,他与其他同事不交流。时而,他会感到饥饿,并试图拿起它相近的两根筷子(筷子在他和他的左或右邻居之间)。一个哲学家一次只能拿起一根筷子。显然,他不能从其他哲学家手中拿走筷子。当一个饥饿的哲学家同时拥有两根筷子时,他就能吃。在吃完后,他会放下两根筷子,并开始思考。
这是一个很经典的同步问题。这个例子满足:在多个进程之间分配多个资源,而不会出现死锁和饥饿。
一种简单的解决方法是:每只筷子都用一个信号量来表示。一个直接学家通过执行操作wait()试图获取相应的筷子,他会通过执行操作signal()以释放相应的筷子。因此,共享数据为 semaphore chopstick[5];
其中,chopstick的所有元素都初始化为1.
代码:
do{
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
...
eat for a while
...
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
...
think for a while
...
}while(true);
以上是可能会导致死锁的问题
如何解决?
措施:
- 允许最多4个哲学家同时坐在桌子上(银行家算法)
- 只有一个哲学家的两根筷子都可用时,他才拿起它们(必须在临界区内拿起两根筷子)
- 使用非对称解决方案。也即:单号的哲学家先拿起左边的筷子,接着右边的筷子;双号的哲学家先拿起右边的筷子,接着左边的筷子
进程通信
- 低级
信号量 pv
- 高级
信箱
类型:
-
共享存储器
-
- 存储区
-
- 公用数据结构
-
消息传递
-
- 直接传递:原语
-
- 间接传递:信箱
-
管道通讯
-
- pipeline 字符流
-
- pipe 无名文件
参考《操作系统概论》
如果转载,请标明出处: