标签:
进程
?
进程间通信总结
?
临界区
定义:对共享内存进行访问的程序片段
?
优秀的解决方案的4个条件
?
实现互斥的方案
适用于内核进程、不适合用户进程
共享锁,初始值为0,测试它
????while (true){
????????while (turn != 1)
????????????critical_region();
????????turn = 0;
????????noncritical_region();
|
?
用于忙等待的锁称为自旋锁
#define FALSE????0 #define TRUE????1 #define N????????2????/*进程数量*/ ? int turn;????????????/*现在轮到谁*/ int interested[N]; /*所有值初始化为0:FALSE*/ ? void enter_region(int process){ /*进程号 0 或 1*/ ????int other; /*其他进程*/ ????other = 1 - process; /*另一方进程*/ ????interested[process] = TRUE;/*表明自己感兴趣*/ ????turn = process;/*设置标志*/ ????while (turn == process && interested[other] == TRUE);/*空语句*/ } ? void leave_region(int process){/*将要离开的进程*/ ????interested[process] = FALSE;/*表明不感兴趣*/ } |
?
Test and Set Lock 测试并加锁
指令如下:
TSL RX, LOCK
它将一个内存字lock读到寄存器RX中,然后再该内存地址上存一个非零值。读字和写字操作保证是不可分割的,即该指令结束之前其他处理器均不能访问该内存字。执行TSL指令的CPU将锁住内存总线,以禁止其他CPU在本指令结束之前访问内存。
?
实现:
?
enter_region:
????????TSL REGISTER, LOCK
????????CMP REGISTER, #0
????????JNE enter_region
????????RET
?
Leave_region:
????????MOVE LOCK, #0
????????RET
?
XCHG 指令 原子性地交换两个位置的内容
实现:
?
enter_region:
????MOVE REGISTER, #1
????XCHG REGISTER, LOCK
????CMP REGISTER, #0
????JNE enter_region
????RET
?
Leave_region:
????MOVE LOCK, #0
????RET
优先级反转:
考虑有两个进程L和H, 优先级 L < H,也就是说,只要H出于就绪状态它就可以运行。 在某一个时刻, L出于临界区中,此时H变到就绪状态,准备运行。现在H开始忙等待, 但由于当H出于就绪态L不会被调度,也就无法离开临界区,所以H将永远忙等待下去。
睡眠与唤醒
错误解法
#define N????100????????/*缓冲区中的槽数*/ int count = 0; ? void producer(void){ ????int item; ????while (true){ ????????item = produce_item(); ????????if (count == N) sleep(); ????????insert_item(item); ????????count++; ????????if (count == 1) wakeup(consumer); ????} } ? void consumer(void){ ????int item; ????while (true){ ????????if (count == 0) sleep(); ????????item = remove_item(); ????????count--; ????????if (count == N - 1) wakeup(producer); ????????consume_item(item); ????} } |
错误原因是对count的访问不加限制。考虑这样的情况,当count == 0 时,consumer 从内存中取得 count准备测试的时候,调度器将consumer换出并执行producer,此时producer生产item,并将count加1, 并猜测 consumer此时一定在休眠中,然而consumer并未休眠(准备测试count或准备进入休眠,被调度器换出),所以wakeup信号将丢失。而当调度器又重新让consumer执行的时候,它测试之前得到的count值 ==0 ,于是进入休眠。Producer继续生产item,总有一刻槽位满了,producer也进入休眠,最终两个进程都陷入无止境的休眠中!
?
信号量(semaphore)
?
适用一个整型变量来累计唤醒次数,以供以后适用。
使用信号量解决生产者-消费者问题
#define N 100 typedef int semaphore; semaphore mutex = 1; semaphore empty = N; semaphore full = 0; ? void producer(void){ ????int item; ????while (true){ ????????item = produce_item(); ????????down(&empty); ????????down(&mutex); ????????insert_item(item); ????????up(&mutex); ????????up(&full); ????} } ? void consumer(void){ ????int item; ????while (true){ ????????down(&full); ????????down(&mutex); ????????item = remove_item(); ????????up(&mutex); ????????up(&empty); ????????consume_item(item); ????} } |
?
二元信号量
mutex 初始值为1,供两个或多个进程适用的信号量。保证同时只有一个进程可以进入临界区,称为二元信号量。
?
互斥量(mutex)
如果不需要信号量的技术能力,有时可以使用信号量的简化版本,称为互斥量。
当一个线程或进程需要访问临界区时,它调用mutex_lock,如果该互斥量当前是解锁的——临界区当前可用,此调用成功,该线程可以进入该临界区。
如果互斥量已经加锁,调用线程被阻塞,直到临界区中的线程完成并调用metux_unlock。
?
mutex_lock 和 mutex_unlock 的实现
mutex_lock: ????TSL REGISTER, MUTEX????????| ????CMP REGISTER, #0 ????JZE ok ????CALL thread_yield ????JMP mutex_lock ok:????RET ? mutex_unlock: ????MOVE MUTEX, #0 ????RET |
?
Pthread中的互斥 Posix 线程库
?
互斥量相关的调用
?
调度
?
批处理调度算法
?
?
交互式系统中的调度算法
时间片设得太短会导致过多的进程切换,降低了CPU效率;而设得太长有可能引起对短的交互请求的响应时间过长
可能产生饥饿现象
CTSS,
如何找到那个最短的进程?
当a = 1/2,有
T0, T0/2 + T1/2, T0/4+T1/4+T2/2, …. 即新的值加上老的值除以2,右移一位
向用户做出明确的性能保证,然后去实现它。比如:若用户工作时有n个用户登录,则用户将获得CPU处理能力的1/n
向进程提供各种系统资源的彩票,一旦需要做出一项调度决策,就随机抽出一张彩票,拥有该彩票的进程获得该资源。
以上的调度策略,调度的是进程自身,并不关心进程的拥有着是谁。
?
实时系统中的调度
特点:正确的但是迟到的回答往往比没有更糟糕。
有m个周期事件,时间i以周期Pi发生,并需要Ci秒的cpu时间
可调度条件:
?
Sigma(i= 1~m) [ Ci/ Pi] <= 1
?
?
线程调度
不用考虑线程属于哪个进程
?
经典的IPC问题
?
哲学家就餐问题
错误的解法
#define N????5 ? void philosopher(int i){ ????while (true){ ????????think(); ????????take_fork(i); ????????take_fork((i + 1) % N); ????????eat(); ????????put_fork(i); ????????put_fork((i + 1) % N); ????} } |
改进:使用一个二元信号量,对think 之后的五个语句进行保护。在开始拿叉之前,哲学家现对互斥量mutex执行down操作。在放回叉子之后,它在对mutex执行up操作。
缺点:性能低下,任一时刻只能有一位哲学家就餐,而5把叉子能够允许两个哲学家同时就餐。
?
?
正确的解法
#define N????????5 #define LEFT????(i+N-1)%N #define RIGHT????(i+1)%N #define THINKING????0 #define HUNGRY????????1 #define EATING????????2 ? typedef int semaphore; int state[N]; semaphore mutex = 1; semaphore s[N]; ? void philosopher(int i){ ????while (TRUE){} } ? void take_forks(int i){ ????down(&mutex); ????state[i] = HUNGRY; ????test(i); ????up(&mutex); ????down(&s[i]); } ? void put_forks(int i){ ????down(&mutex); ????state[i] = THINKING; ????test(LEFT); ????test(RIGHT); ????up(&mutex); } void test(int i){ ????if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING){ ????????state[i] = EATING; ????????up(&s[i]); ????} } |
?
?
?
读者写着问题:
?
在一个读者到达时,且一个写者在等待时,读者在写者之后被挂起,而不是立即允许进入。
一种解法
typedef int semaphore; semaphore mutex = 1; semaphore db = 1; int rc = 0; ? void read(void){ ????while (TRUE){ ????????down(&mutex); ????????rc = rc + 1; ????????if (rc == 1) down(&db); ????????up(&mutex); ????????read_data_base(); ????????down(&mutex); ????????rc = rc - 1; ????????if (rc == 0) up(&db); ????????up(&mutex); ????????use_data_read(); ????} } void writer(void){ ????while (TRUE){ ????????think_up_data(); ????????down(&db); ????????write_data_base(); ????????up(&db); ????} } |
标签:
原文地址:http://www.cnblogs.com/jimmysue/p/4874042.html