进程同步
1.指系统中多个进程中发生的事件存在某种时序关系,需要相互合作,共同完成一项任务
生产者/消费者问题
生产者进程 - 缓冲区 - 消费者进程
1.一个或多个生产者生产某种类型的数据放置在缓冲区中
2.有消费者从缓冲区中取数据,每次取一项
3.只能有一个生产者或消费者对缓冲区进行操作
要解决的问题:
1.当缓冲区已满时,生产者不会继续向其中添加数据
2.当缓冲区为空时,消费者不会从中移走数据
避免忙等待
1.睡眠与唤醒操作(原语)
#define N 100
int 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,初值为1
3.在临界区前实施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路由表的并发访问