- 不确定性: 如果一个操作是非原子操作, 那么就有可能在执行的途中, 由于进程调度通过上下文切换到另一个进程, 最后得到预期以外的结果, 并且由于进程调度可能发生在该操作的任何时刻, 因此结果具有不确定性
- 死锁: 多个进程互相等待对方(可能是互相等待对方任务完成, 或者互相等待对方释放自己所需的资源), 结果永远等不到
- 饥饿: 一个就绪态进程持续等不到CPU调度
临界区: 进程中的一段需要操作共享资源(包括读或者写等等)的代码区域
互斥: 任一时刻最多只能有一个进程位于临界区(无论做读/写操作, 同一时刻只允许一个)
前进原则: 如果一个进程想要进入临界区, 那么在有限时间内一定会等到
方法1:禁用中断: 在进入临界区之前屏蔽中断, 执行完临界区代码后再恢复
缺点:
1.禁用中断不止禁用了上下文切换引起的时钟中断, 同时还禁用了各种外设引起的中断, 因此当临界区比较长时对系统整体性能有很大影响;
2.仅适用单CPU的情况, 对于多CPU系统, 仅禁用一个也没用, 其他CPU仍然可能会调度其他进程进入临界区
方法2:锁: 结合一些原子指令(如test_and_set: 一条机器指令做多件事, 并且不会被打断), 来实现互斥. 支持忙等(不断while, 会占用CPU资源)和非忙等模式(被阻塞时进入睡眠并加入等待队列, 可以减少CPU资源浪费), 适用于多进程和多处理器
缺点:![第3点死锁, 可以通过优先级反转来解决](https:
信号量semaphore: 一个int值, 支持原子操作up和down(也仅有这两个操作可以修改该信号量的值)
![信号量的实现](https:
- up和down: 必须是原子操作, 通常在执行这些操作时屏蔽中断来实现
down: --sem; 若sem<0, 则进程睡眠, 并加入该信号量的进程等待队列;
up: ++sem; 若sem<=0(若明等待队列一定不为空), 则从等待队列中唤醒一个睡眠进程, 让其执行down(通常遵循先来先醒的原则, 唤醒最早进入睡眠的进程)
1.互斥: 利用互斥信号量mutex
2.条件同步:
- 信号量的初始值设置为>=0, 代表可用的空闲资源个数; 当信号量<0, 则信号量的绝对值代表当前正在等待的进程数
* 通过设置信号量的初始值>1, 可以实现让不止一个进程进入临界区
* 互斥量mutex: 信号量取值为0或1, 0表示临界区加锁, 1表示临界区解锁, 用于实现互斥
* 生产者和消费者问题: 通过三个信号量mutex(1), empty(n), full(0)实现
管程monitor:
![在这里插入图片描述](https: