独立的线程:
合作线程:
Race condition(竞态条件)
Atomic Operation(原子操作)
Critical section(临界区)
临界区是指进程中的一段需要访问共享资源并且当另一个进程处于相应代码区域时便不
会被执行的代码区域
Mutual exclusion(互斥)
当一个进程处于临界区并访问共享资源时, 没有其他进程会处于临界区并且访问任何相同
的共享资源
Dead lock(死锁)
两个或以上的进程, 在相互等待完成特定任务, 而最终没法将自身任务进行下去
Starvation(饥饿)
一个可执行的进程, 被调度器持续忽略, 以至于虽然处于可执行状态却不被执行
没有中断, 没有上下文切换, 因此没有并发.
Peterson算法 使用两个共享变量turn和flag处理
Dekker算法
Eisenberg-McGuire算法 处理多进程互斥算法 Bakery算法
软件实现非常复杂, 开锁比较大, 而且很容易出错, 调试困难
硬件提供了一些原语: 中断禁用, 原子操作.
操作系统在些基础上提供更高级的编程抽象: 锁, 信号量
硬件原主指令 (原子操作):
优点:
缺点:
有些进程进入同一个临界区是处理不同任务, 这时使用Lock严重影响系统性能(比如有部分
进程进入是只读的). 那么如何保存多进程进入临界区互斥呢?
Di jkstra提出信号量
Semaphore (信号量) :
两种类型信号量:
信号量可以用在2个方面:
多个信号使用, 粒度小的在里面, 不然容易死锁
monitors, 一开始使用在语言level, 很多条件变量和很多共享资源, 还有对共享资源操作的
一系列函数, 并且有一个Lock.
Lock: - Lock::Acquire() - Lock::Release()
Condition Variable: - Wait() 释放锁, 睡眠 - Signal() 唤醒等待者
多个进程相互持有对方需要的资源锁, 并且等待对方持有的资源, 就造成死锁.
死锁特征(必要条件) 1: 互斥 2: 持有并等待 3: 无抢占 4: 循环等待
处理办法(约束从强到弱):
Deadlock prevention: 打破上面死锁的条件中的一条
Deadlock Avoidance: 使用安全序列, 进程按这个顺列执行就不会死锁. 需要识别safe和
unsafe(包含deadlock), 银行家算法
Deadlock Detection: 死锁检测
Recovery from Deadlock: 出现死锁, 系统可以识别出死锁进程, 按照策略kill进程
IPC(Inter processes communication), 信号(Signal), 管道, 消息队列, 共享内存, 这
里的信号与Lock中的Semaphore不一样.
通信手段, 需要操作系统支持:
进程间通信的类型:
Signal(信号): 软件中断通知事件处理, 不能传输要交换的任何数据, 需要注册信号和信号
产生时处理的函数.
管道(Pipe): 一个进程的输出重定向为另一个进程的输入, stdout和stdin都指向一个buf,
buf大小有限, 父进程是shell
消息队列(Message queues)
共享内存(Shared memory): 直接通信, 最快方式, 必须同步数据访问
套接字(socket)