同步机制

进程互斥和同步

  操作系统引入并发程序设计技术,并发执行的程序由于共享系统资源和协同完成任务需要交互,从而产生进程间的相互依赖和相互制约关系。

  并发进程间的交互存在两种基本关系:竞争关系和协作关系。进程之间的一般交互关系是互斥关系,这是由于计算机中的资源有限,众多进程需要共享资源,当两个进程需要访问同一个独占型资源时,一个进程向操作系统提出资源申请请求,另外一个进程只能等待资源被释放后再申请资源。在竞争关系中,由于进程间共享资源而产生制约关系,这是间接制约关系,又称为互斥关系。互斥机制是解决进程间竞争关系的手段,进程使用互斥机制向系统提出资源申请,谁先向系统提出申请,谁就能先执行。

  同步是并发进程之间共同完成一项任务时直接发生的制约关系,又称为协作关系。具有协作关系的进程在执行的时间次序上,必须遵循确定规律,需要相互协作的进程在某些关键点上协调各自的工作。当其中的一个到达关键点后,在尚未得到其协作进程发来的消息或信号之前应阻塞自己,等待协作进程发来消息或信号后方被唤醒并继续执行。同步机制是解决进程间同步关系的手段,并让并发进程基于某个条件来协调它们的活动,通过合适的方法排定执行的先后次序。

  进程互斥关系是一种特殊的进程同步关系,即逐次使用互斥共享资源,也是对进程使用资源次序上的一种协调。信号量机制是最常用的一种进程同步机制,它能够很好地解决系统态或用户态进程间的竞争关系和协作关系,即同步和互斥关系。

同步机制

  最常用的同步机制有:信号量及PV操作和消息传递和原子操作

原子操作

  原子操作是其他同步方法的基石。原子操作可以保证指令以原子的方式执行———执行过程不被打断。

  内核提供了两组原子操作接口——一组针对整数进行操作,另一组针对单独的位进行操作。

  针对整数的原子操作只能对atomic_t类型的数据进行处理。在这里之所以引入一个特殊的数据类型,而没有直接使用C语言的int类型,主要是出于两个原因:首先,让原子函数只接收atomic_t类型的操作数,可以确保原子操作只与这种特殊类型的数据一起使用。同时,也保证了该类型的数据不会被传递给任何非原子函数。

  atomic_t类型定义在文件<linux/types.h>中:

  typedef struct{

     volatile int counter;

  }atomic_t;

  除了原子整数操作外,内核也提供了一组针对位这一级数据进行操作的函数。位操作函数是对普通的内存地址进行操作的。它的参数是一个指针和一个位号。

自旋锁

  linux内核中最常见的锁是自旋锁,自旋锁最多只能被一个线程所持有。一个被争用的自旋锁使得请求它的线程在等待锁重新可用时自旋(浪费处理器时间),这种行为是自旋锁的要点。所以自旋锁不应该被长时间持有。事实上,这点正是使用自旋锁的初衷:在短期内进行轻量级加锁。还可以采用另外的方式来处理对锁的争用:让请求线程睡眠,直到锁重新可用时再唤醒它。这样处理器就不必循环等待,可以执行其他代码,这也会带来一定的开销——这里有两次明显的上下文切换,被阻塞的线程要被换出和换入,与实现自旋锁的少量几行代码相比,上下文切换当然有更多的代码。信号量便提供了上述第二种锁机制,它使得在发生争用时,等待线程能投入睡眠,而不是旋转。

  linux内核提供了专门的读-写自旋锁,这种自旋锁为读和写分别提供了不同的锁。一个或多个读任务可以并发地持有读者锁;相反,用于写的锁最多只能被一个任务持有,而且此时不能并发的读操作。

  

信号量及PV操作

  信号量实际上是一个整型数,进程在信号量上的操作仅有两种,一种称为P操作,一种称为V操作,在Linux中,P操作也称为Down操作,V操作也被称为Up操作。Down操作让信号量的值减1,Up操作让信号量的值加1。在进行Down操作时,进程先检测信号量的值,如果值大于0,则进程将信号量的值减1,否则进程进入该信号量等待队列,进行睡眠。进程再进行Up操作时,信号量的值被加1,如果此时信号量大于0,睡眠在该信号量等待队列的进程会被唤醒。

  通过信号量,进程能够实现进程间的同步和互斥,信号量的值通常用来表示系统中可用资源的数量,进程通过Down操作来获取系统资源,通过Up操作来释放系统资源。当系统资源不够时,得不到资源的进程会进入等待队列去睡眠,以等待其他进程释放资源后将其唤醒。进程通过对信号量的操作实现进程之间对资源的互斥访问和对同一任务的协同工作。

等待队列

  内核在管理进程时,需要把处于不同状态的进程进行分类组织。处于可运行态的进程被组织在一起。暂停态和僵死态的进程不链接在专门的链表中。等待态的进程在分成很多类,每一个类对应一个特的事件。处于同一类等待态的进程通过等待队列链接在一起。等待队列实现了在事件上的条件等待:希望等待特定事件的进程把自己放在合适的等待队列,并放弃CPU。等待队列表示一组睡眠的进程,当某一条件变成真时,由内核唤醒睡眠的进程。

  

  

  

原文地址:https://www.cnblogs.com/qiaoshanzi/p/3085348.html