操作系统 线程同步 基础知识 (一)
2014-03-26 22:12
197 查看
6.2 临界区问题
临界区问题的解答必须满足以下三项要求:
1. 互斥. 不能有两个线程同时在临界区内执行
2. 前进. 当临界区为空, 而一个线程希望进入临界区时, 该线程进入临界区
3. 有限等待. 一个线程从申请进入临界区到真正进入临界区这段时间不能无限长.
6.3 Peterson 算法
一种软件的方法解决死锁问题, 但也并不能总是解决死锁问题
定义两个变量, 分别为 flag[0/1], turn. flag 表示哪个线程有进入临界区的意愿, turn 表示哪个线程
证明满足上面 3 个要求
1. 互斥. 假设两个线程同时进入临界区, 那么 flag[i] == flag[j] == 1. 当 turn = j 时, 线程 i 在自旋, 不可能进去.
2. 前进. 当线程 j 没有意愿进入临界区时, flag[j] = false; 当 i 有意愿进去时, 直接就进入了.
3. 有限等待. 首先申请临界区的线程进入临界区, 一个线程至多等待另一个线程在临界区执行一次, 满足有限等待.
6.4 硬件同步.
使用原子函数 setAndSwap()
上面的代码核心是 getAndSet 必须时原子操作. 当 lock 为 false 时, 线程上锁进入临界区. 当 lock 为 true 时, 那么 getAndSet 无限循环, 直到 lock 为 false;
6.5 信号量与死锁
当 value 为负时, value 的绝对值对应被阻塞线程的数目.
死锁
上面代码中, P0 执行 S.acquire(), P1 执行 Q.acquire, 然后 P0 执行 Q.acquire, 最后 P1 S.acquire.
然后... 就死锁了
6.6 经典同步问题
1. 有限缓冲区问题
生成者通过 insert 函数向缓冲区内添加 item, 消费者通过 remove 函数在缓冲区内删除 item
信号量有 3 个, 分别为 empty, full, mutex. empty 表示缓冲区内的空格位置, insert 时需要检查缓冲区是否为空, remove 时需要检查缓冲区是否含有元素. mutex 提供对缓冲区的互斥访问
注意, empty, full 都必须使用信号量来表示其剩余个数, 不能用 if 代替
2. 读者写者问题
6.7 管程
管程将 acquire, release 这些操作封装起来了. 管程确保一次只有一个进程能在管程内活动.
管程内的条件遍历有两个操作:
wait() 挂起调用进程并释放管程, 直至另一个进程在条件变量上执行 signal()
signal() 假如有因条件变量被挂起的线程, 那么释放之, 否则什么也不做.
管程实现生产者消费者问题
管程示意图
临界区问题的解答必须满足以下三项要求:
1. 互斥. 不能有两个线程同时在临界区内执行
2. 前进. 当临界区为空, 而一个线程希望进入临界区时, 该线程进入临界区
3. 有限等待. 一个线程从申请进入临界区到真正进入临界区这段时间不能无限长.
6.3 Peterson 算法
一种软件的方法解决死锁问题, 但也并不能总是解决死锁问题
定义两个变量, 分别为 flag[0/1], turn. flag 表示哪个线程有进入临界区的意愿, turn 表示哪个线程
while(true) { flag[i] = true; turn = j; while(flag[j] && turn == j); // let j run first // cirtical section flag[i] = false; // remainer section }
证明满足上面 3 个要求
1. 互斥. 假设两个线程同时进入临界区, 那么 flag[i] == flag[j] == 1. 当 turn = j 时, 线程 i 在自旋, 不可能进去.
2. 前进. 当线程 j 没有意愿进入临界区时, flag[j] = false; 当 i 有意愿进去时, 直接就进入了.
3. 有限等待. 首先申请临界区的线程进入临界区, 一个线程至多等待另一个线程在临界区执行一次, 满足有限等待.
6.4 硬件同步.
使用原子函数 setAndSwap()
void getAndSet(bool var) { swap(lock, var); }
上面的代码核心是 getAndSet 必须时原子操作. 当 lock 为 false 时, 线程上锁进入临界区. 当 lock 为 true 时, 那么 getAndSet 无限循环, 直到 lock 为 false;
6.5 信号量与死锁
acquire() { value --; if(value < 0) { add this process to list block; } } release() { value ++; if(value <= 0) { remove a process P from list wakeup(P); } }
当 value 为负时, value 的绝对值对应被阻塞线程的数目.
死锁
S.acquire(); Q.acquire(); Q.acquire(); S.acquire(); ... ... S.release(); Q.release(); Q.release(); S.release();
上面代码中, P0 执行 S.acquire(), P1 执行 Q.acquire, 然后 P0 执行 Q.acquire, 最后 P1 S.acquire.
然后... 就死锁了
6.6 经典同步问题
1. 有限缓冲区问题
生成者通过 insert 函数向缓冲区内添加 item, 消费者通过 remove 函数在缓冲区内删除 item
信号量有 3 个, 分别为 empty, full, mutex. empty 表示缓冲区内的空格位置, insert 时需要检查缓冲区是否为空, remove 时需要检查缓冲区是否含有元素. mutex 提供对缓冲区的互斥访问
semaphore empty, full, mutex; // init empty = size, full = 0, mutex = 1; // java code public void insert(Object item) { empty.acquire(); mutex.acquire(); buffer[in] = item; in = (in+1) % BUFFER_SIZE; mutex.release(); full.release(); } public Object remove() { full.acquire(); mutex.acquire(); Object item = buffer[out]; out = (out + 1) % BUFFER_SIZE; mutex.release(); empty.release(); return item; }
注意, empty, full 都必须使用信号量来表示其剩余个数, 不能用 if 代替
2. 读者写者问题
// writer may starve void read() { while(true) { mutext.acquire(); readCount ++; if(readCount == 1) { writeLock.acquire(); } mutext.release(); do reading mutext.acquire(); readCount --; if(readCount == 0) { writeLock.release(); } mutext.release(); } } void write() { writeLock.acquire(); do writing writeLock.release(); }
6.7 管程
管程将 acquire, release 这些操作封装起来了. 管程确保一次只有一个进程能在管程内活动.
管程内的条件遍历有两个操作:
wait() 挂起调用进程并释放管程, 直至另一个进程在条件变量上执行 signal()
signal() 假如有因条件变量被挂起的线程, 那么释放之, 否则什么也不做.
管程实现生产者消费者问题
// full means that no space for new added item // empty means that no item for consumer monitor ProducerConsumer { int itemCount; condition full; condition empty; procedure add(item) { if(itemCount == BUFFER_SIZE) { wait(full); } putItemIntoBuffer(item); itemCount ++; if(itemCount == 1) { signal(empty); } } procedure remove() { if(itemCount == 0) { wait(empty); } removeItemFromBuffer(); itemCount --; if(itemCount == BUFFER_SIZE-1) signal(full); } }
管程示意图
相关文章推荐
- 学习笔记:一个操作系统的实现--保护模式之基础知识
- Linux操作系统文件系统基础知识详解
- 操作系统核心原理-4.线程原理(上):线程基础与线程同步
- 操作系统之线程、对称多处理器和微内核--基础知识
- 学习笔记:第2章 操作系统基础知识
- 操作系统相关——操作系统线程基础知识
- Linux操作系统文件系统基础知识
- 操作系统基础知识
- 操作系统之进程的基础知识
- 【软考学习】第二章总结——操作系统基础知识
- Linux操作系统文件系统基础知识详解
- 操作系统基础知识-用户空间实现线程-内核实现线程
- Linux操作系统基础知识之六:系统调用
- Linux操作系统文件系统基础知识详解
- Linux操作系统文件系统基础知识详解
- 专注于操作系统9之保护模式基础知识b
- Linux操作系统文件系统基础知识详解
- 基础知识----symbian操作系统
- JAVA基础知识整理(八) ---操作系统
- Linux操作系统文件系统基础知识详解