进程同步
1.指系统中多个进程中发生的事件存在某种时序关系,需要相互合作,共同完成一项任务
生产者/消费者问题
生产者进程 - 缓冲区 - 消费者进程1.一个或多个生产者生产某种类型的数据放置在缓冲区中2.有消费者从缓冲区中取数据,每次取一项3.只能有一个生产者或消费者对缓冲区进行操作要解决的问题:1.当缓冲区已满时,生产者不会继续向其中添加数据2.当缓冲区为空时,消费者不会从中移走数据避免忙等待1.睡眠与唤醒操作(原语)
#define N 100int count = 0;void producer(void){ int item; while(TRUE){ if(count == N) sleep(); insert_item(item); count = count + 1; if (count == 1) wakeup(consumer) }}void consumer(void){ int item; while(TRUE){ if(count == 0) sleep(); item = remove_item() count = count - 1; if(count == N-1) wakeup(producer); consume_item(item) }}//问题,在消费者做sleep()时被cpu切换下cpu消费者此时上CPU,又生产了一个数据,此时唤醒了空生产者,此时CPU切换回消费者,消费者执行sleep,错误产生了
信号量及P,V操作
1.信号量是一个特殊变量2.用于进程间传递信息的整数值3.定义如下:struc semaphore{ int count; queueType queue;}4.信号量说明:semaphore s;5.对信号量可以实施对操作:初始化,P和V(test,increment)6.PV操作为原语操作
P(s){ s.count--; if(s.count < 0){ 该进程状态置为阻塞状态; 将该进程插入相应的等待队列s.queue末尾 重新调度 }}V(s){ s.count++ if(s.count <= 0){ 唤醒相应等待队列s.queue中等待的一个进程; 改变其状态为就绪态,并将其插入就绪队列 }}
用PV操作解决进程间互斥问题
1.分析并发进程的关键活动,划定临界区2.设置信号量mutext,初值为13.在临界区前实施P(mutex)4.在临界区之后实施V(mutex)
P1:P(mutex)临界区V(mutex)-----------P2:............P(mutex)临界区V(mutex)------------P3:..................P(mutex)临界区V(mutex)//P1首先进入临界区,CPU切换,count此时为-1,P2进入等待队列,CPU切换,count此时为-2,P3进入等待队列,CPU切换到P1,P1完成工作,进行V操作,此时count = -1,将P2加入到就绪队列,CPU切换到P2,P2完成工作,执行V操作,将P3加入到就绪队列
用信号量解决生产者/消费者问题
#define N 100 //缓冲区个数#typedef int semaphore //信号量是一种特殊的整型类型#semaphore mutex =1 //互斥信号量,控制对临界区的访问#semaphore full = 0 //满缓冲区个数void producer(void){ int item; while(TRUE){ item = produce_item(); P(&empty) P(&mutex) insert_item(item) V(&mutex) V(&full) }}void consumer(void){ int item; while(TRUE){ P(&full); P(&mutex) item = remove_item() V(&mutex) V(&empty) consume_item(item) }}
用信号量解决读者/写着问题
1.多个进程共享一个数据区,读者进程,只读数据,写者进程,只写数据2.满足条件: 1.允许过关读者同时执行读操作 2.不允许多个写着同时操作 3.不允许读者,写者同时操作
第一类读写者问题:读者优先
如果读者执行:1.无其他读者,写者,该读者可以读2.若已有写者等,但又其他读者正在读,则该读者也可以读3.若有写者正在写,该读者必须等如果写者执行:1.无其他读者,写者,该读者可以写2.若又读者正在读,该写者等待3.若又其他写者正在写,该写者等待
void render(void){ while(TRUE){ P(mutex) //对rc临界资源做保护 rc = rc + 1; if(rc == 1)P(w) //第一个读者 读操作 V(mutex) P(mutex) rc = rc -1; if(rc == 0)V(w) //最后一个读者 V(mutex) }}void writer(void){ while(TRUE){ ... P(w) 写操作 V(w) }}
LINUX提供对读写锁
1.应用场景 如果每个执行实体对临界区对访问或者是读或者是写共享变量,但是他们都不会既读又写时,读写锁是最好读选择3.实例:linux读IPX路由代码中使用了读写锁,用ipx_routes_lock的读写锁保护IPX路由表的并发访问