同步机制

文章目录

  • 进程互斥
    • 临界资源与临界区
    • 临界区的使用原则
  • 进程互斥的软件解决方案
    • 错误解法
    • Dekker算法
    • Peterson算法
  • 进程互斥的硬件解决方案
    • “测试并加锁”指令
    • “交换”指令
  • 进程同步
  • 信号量及PV操作
    • 用PV操作解决进程间互斥问题
    • 用信号量解决生产者-消费者问题
    • 用信号量解决读者-写者问题
  • 管程
    • 互斥/同步
    • Hoare管程
      • 条件变量
      • 用管程解决生产者-消费者问题
    • MESA管程
  • IPC(进程间通信)
    • 管道
    • FIFO
    • 消息队列
    • 信号量
    • 共享内存
    • 套接字
  • 参考资料

进程互斥

由于各进程要求使用共享资源(变量、文件等),而这些资源需要排他性使用,各进程之间竞争使用这些资源,这一关系称为进程互斥。

临界资源与临界区

系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源或共享变量。

而各个进程中对某个临界资源(共享变量)实施操作的程序片段称为临界区或互斥区。

临界区的使用原则

  • 没有进程在临界区时,想进入临界区的进程可进入
  • 不允许两个进程同时处于其临界区中
  • 临界区外运行的进程不得阻塞其他进程进入临界区
  • 不得使进程无限期等待进入临界区

进程互斥的软件解决方案

错误解法

考虑两个进程p和q,pturn与qturn表示哪个进程要进入临界区,P进入临界区的条件为,而Q进入临界区的条件为:

如果由于CPU调度使得两个进程都执行完了第一行语句,也就是pturn和qturn都为true了,那么就都会在下一行while语句上死循环,互相都在谦让对方执行,也就不满足了临界区的使用原则—不得使进程无限期等待进入临界区。

Dekker算法

Dekker互斥算法是由荷兰数学家Dekker提出的一种解决并发进程互斥与同步的软件实现方法。假设有p和q两个进程,变量pturn、qturn表示p和q进程是否想要资源(可以想象为举手示意想要),变量turn表示安排资源给谁:

如果两个进程都执行完了第一行语句,也就是pturn和qturn都为true了,那么会根据变量turn进一步查看究竟是把资源安排给了谁,如果安排给了另一个进程,那么自己就先把手放下,等待安排资源给自己。

与之前的错误解法相比,可以发现Dekker算法就是在原本的while死循环上做了进一步的判断,引入的turn变量总是会安排一个进程访问临界区。

Peterson算法

Peterson算法是另一种解决并发进程互斥与同步的软件实现方法,而且克服了强制轮流法的缺点。其使用十分方便,只需要向如下这样调用即可:

其中的方法实现如下:

如果有两个进程都要执行的话,turn会被设置成后一个进程的进程号,这时候因为要按照先来后到的规矩,后一个进程在判断while条件的时候成立,也就进行循环等待,而先进入的进程可以访问临界区。当先进入的进程离开了临界区,就调用方法,将自己的兴趣设为FALSE,后一个进程判断不成立时就可以跳出while循环进入临界区了。

进程互斥的硬件解决方案

“测试并加锁”指令

XCHG

进程同步

进程同步指系统中多个进程中发生的事件存在某种时序关系,需要相互合作,共同完成一项任务。
具体地说,一个进程运行到某一点时, 要求另一伙伴进程为它提供消息,在未获得消息之前,该进程进入阻塞态,获得消息后被唤醒进入就绪态。

信号量及PV操作

信号量是一个特殊变量,用于进程间传递信息的一个整数值,定义如下:

可以对其执行down和up操作,也就是常见的P和V操作(PV操作均为原语操作),定义如下:

用PV操作解决进程间互斥问题

  • 分析并发进程的关键活动,划定临界区
  • 设置信号量 mutex,初值为1
  • 在临界区前实施 P(mutex)
  • 在临界区之后实施 V(mutex)

用信号量解决生产者-消费者问题

问题描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。

这里使用三个信号量,其中mutex用于解决互斥问题,empty和full用于解决同步问题。

注意:不能交换和的顺序,否则会导致死锁。

用信号量解决读者-写者问题

问题描述:多个进程共享一个数据区,这些进程分为只读数据区中的数据的读者进程和只往数据区中写数据的写者进程。允许多个读者同时执行读操作,不允许多个写者同时操作,不允许读者、写者同时操作。

typedef int semaphore;semaphore count_mutex = 1;	//对count加锁semaphore data_mutex = 1;	//对读写的数据加锁int count = 0;	//对数据进行读操作的进程数量void reader() {    while(TRUE) {p(&count_mutex);count = count + 1;if(count == 1) p(&data_mutex); // 第一个读者需要对数据进行加锁,防止写进程访问v(&count_mutex);read();p(&count_mutex);count = count - 1;if(count == 0) v(&data_mutex);v(&count_mutex);    }来源:水木今山
                                                        

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年10月7日
下一篇 2018年10月7日

相关推荐