1.基本概念
在多道程序系统中,由于进程,各进程之间有两种形式的制约关系:
(1)间接相互制约– 源于资源共享 -互斥。
(2)直接相互制约– 源于进程合作 -同步。
进程同步:主要源于进程合作,为进程之间的直接制约关系。
进程互斥:主要源于资源共享,是进程之间的间接制约关系。
临界资源:一次只允许一个进程使用的资源称为临界资源,如打印机、公共变量等。
临界区:在每个进程中,访问临界资源的那段程序称为临界区。
2.同步机制应遵循的准则
(1)空闲则进:当临界区空闲时,进程可以立即进入,以便有效地利用临界资源。
(2)遇忙等待:当已有进程进入其临界区时,其它进程必须等待,以保证互斥。
(3)有限等待:对要求进入的进程,应在有限的时间内使之进入,以免陷入“死等”。
(4)让权等待:对于等待的进程,它必须立即释放处理机,以避免进程忙等。
1.用软件实现的同步互斥机制
(1)算法一:单标志法
(2)算法二:双标志法先检查
(3)算法三:双标志法后检查
(4)算法四:Peterson’sAlgorithm
2.进程互斥的硬件方法
(1)检测和设置(TS)指令
(2)swap指令(或exchange指令)该指令的作用是交换两个字(字节)的内容
1.对信号量S进行 P操作,记为P(S),处理过程如下
--S.Q; //表示申请一个资源 if (S.Q < 0) //表示没有空闲资源 { 调用进程进入等待队列 S.Q; 阻塞调用进程; }
2.对信号量S进行 V操作,记为V(S),处理过程如下
++S.Q; //表示释放一个资源 if (S.Q <= 0) //表示有进程处于阻塞状态 { 从等待队列 S.Q 中取出一个进程 P; 进程 P 进入就绪队列; }
一个管程定义了一个数据结构和能为并发进程所运行的一组操作,这组操作能同步进程和改变管程中的数据。
管程由三部分组成:
局部于管程的共享数据说明;
对该数据结构进行操作的一组过程;
对局部于管程的数据设置初始值的语句。
1.生产者-消费者问题
用C语言和信号量机制描述生产者-消费者问题的程序如下:有界缓冲区的大小为100。
#define N 100 //有界缓冲区大小 typedef int semaphore; //定义信号量 semaphore mutex = 1; //临界区互斥信号量 semaphore empty = N; //空闲缓冲区 semaphore full = 0; //缓冲区初始化为空 void producer(void) { int item; //局部变量 while(1) { item = produce_item(); //生产数据 P(empty); //获取空数据槽 P(mutex); //获得进入临界区的信号量 insert_item(item); //将数据放入缓冲池 V(mutex); //释放互斥量 V(full); //数据量加一 } } void consumer(void) { int item; //局部变量 while(1) { P(full); //获取数据槽 P(mutex); //获得进入临界区的信号量 item = remove_item(); //将数据从缓冲池读出 V(mutex); //释放互斥量 V(empty); //数据量减一,即空槽加一 consume_item(item); //消费数据 } }
2.读者-写者问题
设置互斥信号量wmutex表示写者间、读者和写者间互斥,用readcount变量来记录读者数,由于readcount是读者间共享变量,属于临界资源,它也需互斥,为此,又增设互斥信号量rmutex。程序如下:
typedef int semaphore; //定义信号量 semaphore rmutex = 1; //读者计数器的互斥量 semaphore wmutex = 1; //写-写,读-写互斥量 int readcount = O; //读者计数器 void reader(void) //读者进程 { while (1) //进程被调度 { P(rmutex); //取得读者计数器的互斥量 readcount = readcount + 1; //进来一个读者,读者数量加一 if (readcount == 1) //如果是第一个读者,取得读-写互斥量 P(wmutex); V(rmutex); //释放读者计数器的互斥量 read_data_base(); //读数据 P(rmutex); //读者读完数据要离开,先取得读者计数器的互斥量 readcount = readcount – 1; //读者数量减一 if(readcount == O) //如果是最后一个离开的读者,释放读-写互斥量 V(wmutex); V(rmutex); //释放读者计数器的互斥量 use_dataread(); //读者使用数据 } } void writer(void) //写者进程 { while (1) //进程得到调度 { think_up_data();//写者产生数据 P(wmutex); //获得写-写,读-写操作互斥量 write_data_base(); //写入数据库 V(wmutex); //释放写-写,读-写操作互斥量 } }
3.哲学家进餐问题-解决办法
(1)至多只允许四个哲学家同时进餐,以保证至少有一个哲学家可以获得二只筷子:
typedef int semaphore; //定义信号量 semaphore chopstick[5]= {1,1,1,1,1}; //初始化信号量 semaphore eating = 4; //仅允许四个哲学家可以进餐 void philosopher(int i) //第 i 个哲学家的程序 { while(1) { thinking(); //工作之一 P(eating); //请求进餐,若是第五个则先挨饿 P(chopstick[i]); //请求左手边的筷子 P(chopstick[(i+1)%5]); //请求右手边的筷子 eating(); //进餐 V(chopstick[(i+1)%5]); //释放右手边的筷子 V(chopstick[i]); //释放左手边的筷子 V(eating); //释放信号量给其他挨饿的哲学家 } }
(2)另一种解决方法,仅当哲学家的左、右两支筷子均可用时,才允许他拿起筷子进餐。
typedef int semaphore; //定义信号量 semaphore chopstick[5]= {1,1,1,1,1}; //初始化信号量 semaphore mutex = 1; //设置取筷子的信号量 void philosopher(int i) //第 i 个哲学家的程序 { while(1) { thinking(); P(mutex); //在取筷子前获得互斥量 P(chopstick[i]); P(chopstick[(i+1)]%5); V(mutex); //释放互斥量 eating(); V(chopstick[(i+1)]%5); V(chopstick[i]); } }
(3)规定奇数号哲学家先拿起其左边筷子,然后再去拿右边筷子;而偶数号哲学家则相反。程序代码如下:
typedef int semaphore; //定义信号量 semaphore chopstick[5]= {1,1,1,1,1}; //初始化信号量 void philosopher(int i) //第 i 个哲学家的程序 { while(1) { thinking(); if(i%2 == 0) //偶数哲学家,先右后左 { P(chopstick[i+1]%5); P(chopstick[i]); eating(); V(chopstick[i+1]%5); V(chopstick[i]); } else //奇数哲学家,先左后右 { P(chopstick[i]); P(chopstick[i+1]%5) ; eating(); V(chopstick[i]); V(chopstick[i+1]%5); } } }
原文地址:http://blog.csdn.net/zjf280441589/article/details/37936751