进程同步 订阅
进程同步:在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。 [1] 展开全文
进程同步:在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。 [1]
信息
外文名
Process Synchronization
所属范围
计算机技术
中文名
进程同步
进程同步同步的概念
我们把异步环境下的一组并发进程因直接制约而互相发送消息、进行互相合作、互相等待,使得各进程按一定的速度执行的过程称为进程间的同步。具有同步关系的一组并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件。 如果我们对一个消息或事件赋以唯一的消息名,则我们可用过程 wait (消息名)  表示进程等待合作进程发来的消息,而用过程 signal (消息名) 表示向合作进程发送消息。 [2] 
收起全文
精华内容
下载资源
问答
  • 进程同步

    2019-04-13 18:33:11
    为什么要引入进程同步? 在多道程序环境下,程序是并发执行的,不同进程之间存在着不同的相互制约关系,为了协调进程之间的相互制约关系,引入了进程同步的概念。在操作系统中,要对并发进程进行同步的原因是并发...

    基本概念

    为什么要引入进程同步?

    在多道程序环境下,程序是并发执行的,不同进程之间存在着不同的相互制约关系,为了协调进程之间的相互制约关系,引入了进程同步的概念。在操作系统中,要对并发进程进行同步的原因是并发进程是异步的。

    临界资源

    一次仅允许一个进程使用的资源称为临界资源,如打印机、公用队列等。对临界资源的访问必须互斥地进行。在每个进程中,访问临界资源的那段代码称为临界区。
    临界资源的访问分为4个部分:
    ①进入区:检查可否进入临界区,若可以进入,则设置标志。
    ②临界区:进程中访问临界资源的那段代码,又称临界段。
    ③退出区:清除标志。
    ④剩余区:代码中的其他部分。

    同步

    同步又称直接制约关系。是指为了完成某个任务而建立的两个或多个进程,这些进程需要协调工作次序,它们的制约关系源自它们之间的相互合作。
    例:读进程和写进程对同一段缓冲区的读和写。

    互斥

    互斥又称间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。
    例:访问打印机。
    同步机制应该遵循以下准则:
    ①空闲让进。临界区空闲可以允许进程进入。
    ②忙则等待。已有进程进入临界区则其他进程必须等待。
    ③有限等待。对请求访问的进程,保证在有限时间内进入临界区。
    ④让权等待。当进程不能进入临界区应立即释放处理器。

    展开全文
  • 经典的进程同步问题

    万次阅读 多人点赞 2018-08-04 14:23:33
    经典的进程同步问题 普通版:一类进程作为生产者,生产产品,生产的产品放入一个缓冲区,消费者从缓冲区中取出产品,需要保证生产者不可以向满的缓冲区中添加产品,消费者不可以从空的缓冲区中取出产品。同一时刻...

    经典的进程同步问题

    普通版:一类进程作为生产者,生产产品,生产的产品放入一个缓冲区,消费者从缓冲区中取出产品,需要保证生产者不可以向满的缓冲区中添加产品,消费者不可以从空的缓冲区中取出产品。同一时刻只可以有一个生产者生产产品或者消费者消费产品。

    升级版可以实现同一个时刻既有生产者生产产品,又有消费者消费产品。但是绝对不可以同一时刻多个生产者生产产品或者多个消费者消费产品。同时使用count记录缓冲区中产品的数量。

    • 生产者消费者问题

      1)生产者进程和消费者进程都以异步方式运行, 但它们之间必须保持同步。

      2)可利用互斥信号量$mutex$实现诸进程对缓冲池的互斥使用(不可以同时既向缓冲区中放入数据,又从缓冲区中拿出数据);利用资源信号量empty和full分别表示缓冲池中空缓冲池和满缓冲池的数量。 假定这些生产者和消费者相互等效

      /*
      in表示放入数据的地址,out表示取出数据的地址
      buffer[n]:表示大小为n的缓冲池(由多个缓冲区组成) 
      mutex,mutex1,mutex2:互斥型信号量,初值为1
      empty,full:资源型信号量,empty表示空缓冲区的数量,full表示满缓冲区的数量
      item:表示一个数据项
      */
      Int in=0,out=0;  
      Item buffer[n];   
      Semaphore mutex1=1,mutex2 = 1,empty=n,full=0;  
      
      //生产者
      Void producer(){ 
       	do{
      		生产一个产品放入nextp;
              
              /*
               * 进入区
               * 先申请资源信号量,在申请互斥信号量
               * mutex1控制同一个时间段内只能有一个生产者生产产品
               */
      		wait(empty);
      		wait(mutex1);
              
              /*临界区*/
      		buffer[in]=nextp;
      		in=(in+1) % n;
              
              /*退出区*/
      		signal(mutex1);
      		signal(full);
              
              /*对计数器count的互斥访问*/
              wait(mutex);
              count++;
              signal(mutex);
      	}while(TRUE)
      }
      
      //消费者
      Void consumer(){ 
          do{
             /*进入区*/
      	   wait(full);
      	   wait(mutex2);     //消费者对缓冲区的互斥访问
             
             /*临界区*/
      	   nextc =buffer[out];          //只有一份
      	   out =(out+1) mod n;
              
             /*退出区*/
      	   signal(mutex2);
      	   signal(empty);
              
              /*对计数器count的互斥访问*/
              wait(mutex);
              count--;
              signal(mutex);
      	   消费 nextc中的产品;                        
      	}while(TRUE)
      }
      
      
      Void main(){
      	cobegin
      	    proceducer();
       	    consumer();
      	coend
      }

      注意:

      1)每个程序的互斥操作wait()和signal()必须成对的出现。

      2)输入进程不可以向满的缓冲池中输入数据,计算进程不可以从空的缓冲池中取数据

      3)在每个程序中的多个wait操作顺序不能颠倒,必须先执行对资源信号量的wait操作,在进行对互斥信号量的wait操作,否则可能引起进程死锁。

      4)可以使用三个互斥信号量mutex、mutex1、mutex2实现同一时刻既有生产者生产,又有消费者消费。

    • 读者—写着问题

      该问题涉计两类进程,第一类进程是读进程Reader,另一类进程是写进程Writer,多个读进程可以同时读一个文件(共享资源),多个写的进程不可以同时写一个文件(对写互斥),并且读的时候不能写,写的时候不能读(对读互斥)。

      1)问题核心:保证一个Writer进程必须与其他进程互斥地访问共享对象的同步问题。

      2)只要求读文件的进程称为“Reader进程”,其它进程则称为“Writer进程”。

      3)允许多个进程同时读一个共享对象,但不允许一个Writer进程和其他Reader进程或Writer进程同时访问共享对象(共享对象并不是临界资源,因为他允许多个进程对其访问)

      /*
      记录型信号量解决读者—写者问题
      
      rmutex:读进程对Readcount的互斥
      wmutex:writer对reader和writer的互斥
      readcount:表示正在读的进程数目,只有当readcount=0的时候才需要申请wmutex权限,大于0的时候不需要
      */
      
      semaphore rmutex=1, wmutex =1;
      int readcount =0;
      Void Reader(){
      	do{
      		wait(rmutex);          //防止多个reader进程对readcount的访问
      		if (Readcount==0){    //如果readcount不等于0,表示有进程正在进行读操作,绝对没有写操作
      			wait(wmutex);
      		}
      		Readcount ++;
      		signal(rmutex);
      		…
      		读;
      		…
      		wait(rmutex);
      		Readcount - -;
      		if (Readcount==0){      //只有等于0的时候才需要释放资源,使得写进程可以工作
      			signal(wmutex);
      		}
      		signal(rmutex);
      	}while(TRUE);
      }
      Void writer(){
          do{
              wait(wmutex);      //申请写权限的资源
              写;
              signal(wmutex);
          }while(TRUE);
      }
      
      Void main(){
          cobegin
             reader();  writer();
      	Coend
      }

      利用信号量集的机制实现读者-写者问题

      int RN;
      semaphore L = RN;             //表示读者的数量
      mx = 1;						//对写者进行互斥的访问
      
      void Reader(){
          while(true){
              Swait(L, 1, 1);         //申请一个读者进程
              Swait(mx, 1, 0);       //判断当前是否有写者进程在写,该出相当于一个开关
              
              operation...
                  
              Ssignal(L, 1);
          }
      }
      
      void Writer(){
          while(true){
              //此处首先申请一个mx,如果当前系统中无写者进程,则该语句必定执行成功,Reader进程中的
              //Swait(mx, 1, 0)便处于关闭状态,只需要等系统中的读进程执行完毕,(L, RN,0)执行成
              //功,打开开关即可。
              Swait(mx, 1, 1; L, RN, 0);
              
              operation...;
              
              //释放一个写进程
              Ssignal(mx, 1);
          }
      }
      
      void main(){
          cobegin
              Reader();
          	Writer();
          coend;
      }

       

    • 哲学家的进餐问题

      五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在桌子上有五只碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐毕,放下筷子继续思考。

      /*
      记录型信号量解决问题
      */
      //每一只筷子均为临界资源
      semaphore chopstick[5]={1,1,1,1,1};
      //所有的信号量均被初始化为1,第i位哲学家的活动可描述为:
      do{
      	wait(chopstick[i]);          //拿左手的筷子
      	wait(chopstick[(i+1) mod 5] );      //拿右手的筷子
      	…
      	eat;
      	…
      	signal(chopstick[i]);    //放左手
      	signal(chopstick[(i +1)mod 5]);       //放右手
      	…
      	think;
      }while(TRUE);

      存在的问题:假如五位哲学家同时饥饿而各自拿起左边的筷子时,就会使五个信号量chopstick均为0,当他们再试图去拿右边的筷子时,都将因无筷子可拿而无限等待。进入死锁状态。

      解决办法:

      **1)**至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕后释放出他用过的两只筷子,从而使更多的哲学家能够进餐。

      semaphore chopstick[5]={1,1,1,1,1};
      semaphore count=4;
      void philosopher(int i)
      {
          while(true)
          {
              think();
              wait(count); //请求进入房间进餐
              wait(chopstick[i]); //请求左手边的筷子
              wait(chopstick[(i+1)%5]); //请求右手边的筷子
              eat();
              signal(chopstick[(i+1)%5]); //释放右手边的筷子
              signal(chopstick[i]); //释放左手边的筷子
              signal(count); //退出房间释放信号量
          }
      }

      **2)**仅当哲学家的左右两只筷子均可用时,才允许他拿起筷子进餐。

      /*
      使用AND型信号量解决,本质当同时拥有两只筷子的时候才允许拿起筷子进餐
      */
      semaphore chopstick[5]={1,1,1,1,1};
      Philosopher i
      do{
      	think;
      	Swait(chopstick[(i+1)mod 5],chopstick[i ]);     //同时分配两只筷子
      	eat;
      	Ssignal(chopstick[(i+1)mod 5], chopstick[i ] );     //同时放下两只筷子  
      }while(TRUE)

      **3)**规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;偶数号哲学家则相反。

      semaphore chopstick[5]={1,1,1,1,1};
      //第i 位哲学家的活动可描述为:
      do{
          //奇数位哲学家先拿左手的筷子
      	if  i mod 2=1 {
      		wait(chopstick[ i ]);
      		wait(chopstick[ ( i +1) mod 5] )
      	}
          //偶数位哲学家先拿右手边的筷子
      	else
      	{
      		wait(chopstick[ ( i +1) mod 5] );
      		wait(chopstick[ i ])
      	}
      	eat;
      	signal(chopstick[ i ]);
      	signal(chopstick[(i +1)mod 5]);
      	…
      	think;
      }while(TRUE)

     

    展开全文
  • 进程同步和通信 进程同步 在OS中引入进程后,一方面使系统的吞吐量和资源的利用率得到提升,另一方面也使得系统变得复杂,如果没有合理的方式对进程进行妥善的管理,必然会引起进程对系统资源的无序竞争,使系统...

    进程同步和通信

    进程同步

    在OS中引入进程后,一方面使系统的吞吐量和资源的利用率得到提升,另一方面也使得系统变得复杂,如果没有合理的方式对进程进行妥善的管理,必然会引起进程对系统资源的无序竞争,使系统变得混乱;为了实现对并发进程的有效管理,在多道程序系统中引入了同步机制,常见的同步机制有:硬件同步机制、信号量机制、管程机制等,利用它们确保程序执行的可再现性;

    进程同步的基本概念

    两种形式的制约关系

    1. 间接相互制约:由于多个进程并发执行时,共享系统资源,致使这些进程在执行时形成相互制约的关系。为了使共享系统资源的进程有序执行,系统资源必须统一分配,即进程需要先申请后使用;
    2. 直接相互制约:多个进程为了完成同一项任务而合作,在合作过程中形成相互制约的关系;

    这里所说的制约关系,其实是一种相互影响的关系,即某一个进程的运行除了受到系统影响外还会受到其他进程运行情况的影响;而上面两种分类方式的依据是产生影响的原因;

    临界资源

    在操作系统引论中介绍操作系统的四大特性之一“共享”时曾提到,对于资源的共享有两种方式:互斥共享和同时访问。其中需要互斥访问的资源就是临界资源;所谓互斥访问,就是指在进程A对资源X的处理结束前,其他进程不允许对X进行处理;这里的临界资源既包括硬件资源也包括软件资源;

    临界区

    对于临界资源进行访问的代码,即为临界区;在进入临界区之前,需要检查是否可以访问互斥资源,这一部分代码即为进入区;在退出临界区时,需要释放对临界资源的占有,这一部分代码即为退出区;然后我们把剩下的其余代码成为剩余区

    同步机制应遵守的规则

    1. 空则让进:临界资源如果处于空闲状态,那么该进程可以进入其临界区;
    2. 忙则等待:临界资源如果处于被占用状态,那么该进程需要等待临界资源被释放;
    3. 有限等待:进程在有限时间内可以进入自己的临界区,以避免陷入“死等”状态;
    4. 让权等待:当进程不能进入自己的临界区时,需要让出处理机,以避免陷入“忙等”状态;

    进程同步的方式

    硬件同步机制

    利用软件方法可以解决进程互斥进入临界区的问题,但是有一定的难度和局限性,现已很少使用。通常计算机会提供一些特殊的硬件指令,允许对一个字中的内容进行检测和修正,或者对两个字的内容进行交换;对临界区的管理,可以视为对“锁”的管理:当“锁”开的时候,就允许进入,然后把“锁”关上;当“锁”关上的时候,就只能在外面等待;显然,对“锁”的检测(相当于进入区代码)和打开“锁”(相当于临界区)的操作必须是连续的;常见的硬件同步机制有:

    1. 关中断

      是实现互斥的最简单方法之一。在进入锁检测之前,关闭中断,知道完成锁检测并上锁之后才打开中断。这样,进程在临界区执行期间,计算机系统不响应中断,从而不会引发调度,自然不会发生进程或者线程切换。但是关中断的方法有许多缺点:1。滥用关中断权利,可能会造成严重后果;2. 关中断时间过长,会影响系统效率,限制处理器交叉执行程序的能力;3.关中断的方法不适合多CPU系统;

    2. 利用Test-and-Set 指令实现互斥

      TS指令的一般描述如下:

      boolean TS(boolean *lock){
          boolean old;
          old=*lock;
          *lock=true;
          return old;
      }
      相应的进入区代码为:
      while(TS(&lock));
      

      TS指令中,当lock为false时,就将其设置为true,然后返回false;当lock为true时,就返回true;

      返回false表示资源可用;返回true表示资源不可用;

      上面这段代码实现的功能:如果lock为false,那么设置它为true,但是要返回false;如果lock为true,不做改变,那么仍旧返回true;但实际上,它是这么做的:不论lock是什么,都把它设置为true。而返回它原来的值;

    3. 利用Swap指令实现互斥

      void Swap(boolean* lock,boolean* key){
          	boolean temp=*lock;
          	*lock=*key;
          	*key=temp;
      }
      相应的进入区代码为:
      key=true;
      do{
          Swap(&lock,&key);
      }while(key!=false);
      //进入临界区
      

      Swap指令中,do-while循环中的退出条件是key为false ;而key为false 意味着lock为false,表示资源可用;当lock为true的时候,key就为true;那么循环就会一直进行下去;感觉还是蛮绕的,分类看看:

      进入Swap之前 进入Swap之后 是否再次进入Swap
      lockfalse,keytrue(资源可用) locktrue,keyfalse(允许进入临界区)
      locktrue,keytrue(资源不可用) locktrue,keytrue(不允许进入临界区)

      这里,我们可以看出,当资源不可用是,进入Swap并没有任何改变,这是符合功能的:资源不可用,当然检查多少遍都不可用嘛;

      由于资源是共享的,所以这里的lock作为资源的标记之一,必然会被多个进程访问,所以,当一个拥有资源的进程使用完该资源的时候,需要将lock设置为false,以便让其他进程使用,这就是退出区代码的任务啦;

      利用TS机制和Swap机制,都会让进程处于忙等状态,并不符合同步机制的要求;(准确的说,不是实现不了同步,而是效率不高,不太高效~)

    信号量同步机制

    信号量同步机制由Dijkstra(很厉害的大神,单源最短路劲算法就是他提出的);信号量机制已被广泛应用到单处理机和多处理机系统以及计算机网络中;

    1. 整型信号量

      整型信号量S表示资源数目,除初始化外,仅能通过两个标准的原子操作进行修改:wait(S)和signal(S);这两个操作长期以来也别称为P、V操作;

      wait(S){
          while(S<=0);
          S--;
      }
      signal(S){
          S++;
      }
      

      其实问题就是,wait和signal两个原子操作仍旧会产生“忙等”——进程不断测试,一直问,你说烦不烦?

    2. 记录型信号量

      记录型信号量机制是一种不存在忙等现象的进程同步机制;但是采取了让权等待策略后,就会有多个进程等待访问统一资源的情况,于是还需要把这些进城组织起来,于是除了S用来表示资源的数量外,还需要一个指针;这也是记录型信号量的名称来源:使用了记录型的数据结构;

      typedef struct{
          int value;
          sturct process_control_block *list;
      }semaphore;
      wait(semaphore *S){
          S->value--;
          if(S->value<0){
              block(S->list);
          }
      }
      signal(semaphore *S){
          S->value++;
          if(S->value<=0){
              wakeup(S->list);
          }
      }
      

      记录型信号量中,value不仅指示资源的数量,由于每次wait操作value都会递减,所以value的值会反映出等待资源的进程有多少个。在signal中,value经过自增后,如果还<=0,说明还有进程在等待该资源,所以需要wakeup一个进程;

    3. AND型信号量

      前面所述的进程互斥问题针对的是多个并发进程共享一个临界资源的情况,但是如果多个进程共享多个资源时仍旧采取这样单个的分配方法,就有可能发生死锁现象;为了避免这样的现象,提出来AND型信号量:将进程在整个运行过程中需要的所有资源,要么一次性全部分配给进程,然后使用完后再一起释放。要么一个都不分配,这样便可以避免死锁现象。wait和signal操作要做出相应改变。

      Swait(S1,S2,S3,S4,S5....){
      	while(true){
              if(S1>=1&&S2>=1...){
             		for(i=1;i<=n;i++){
                  	Si--;
              	}
              	break;
          	}else{
                  //找到第一个小于等于0的Si,然后将进程放置到与其相关的等待队列中
          	}
      	}
      }
      Ssignal(S1,S2...Sn){
          while(true){
              for(i=0;i<=n;i++){
                  Si++;
                  //唤醒一个等待Si资源的进程——该进程将进入Swait中的while循环里继续判断其他资源是否可用。
              }
          }
      }
      
      
    4. 信号量集

      前面介绍的几种信号量同步机制都是对某一资源进行一个单位的申请和释放。当一次需要N个的时候,就需要进行N次请求,这不但低效而且容易发生死锁情况;还有些情况下,为了保证系统的安全性,当所申请的资源低于某个值时,就需要停止对该类资源的分配。解决办法就是当进程申请某类临界资源时,都必须测试资源的数量,判断是否大于可分配的下限值,然后决定是否分配;

      基于上述提到的两点问题,需要对AND信号量机制加以扩充,对进程所申请的所有资源以及每类资源不同的资源需求量,再一次PV原语操作中完成申请和释放。对信号量Si的测试值不再是1,而是ti。当Si<=ti时就不再分配;同时,进程需要传递给wait方法每类资源所需要的数目,由此形成一般化的“信号量集”机制;

      Swait(S1,t1,d1....Sn,tn,dn);表示对Si类资源的需求是di个,当Si的数量小于ti时就不再分配;
      Ssignal(S1,d1....Sn,dn);表示归还Si类资源的数目是di个;
      

      特殊的,Swait(S,d,d)表示信号量集中只有一个信号量;它允许每次申请d个资源,当资源数量小于d时不予分配;

      Swait(S,1,1)表示普通的一般记录型信号量;

    信号量的应用:

    1. 实现进程互斥:基本操作;
    2. 实现前驱关系:当进程A中的X1操作结束后才进行进程B中的X2操作,像这种需求即为前驱关系。可以设置一种虚拟的资源S,并设置其状态为不可用,然后在X1的后面加上signal(S),在X2语句前加上wait(S),以此实现这种执行顺序上的控制;

    管程机制

    信号量机制虽然是一种既方便又实用的进程同步机制,但是要访问临界资源的进程需要自备同步操作wait(S)和signal(S),这就使得对共享资源进行访问的代码遍布各个进程,不利于系统管理,还增加系统死锁的风险;管程机制是一种解决该问题的方法;

    操作系统的作用之一就是实现对计算机系统资源的抽象,管程机制使用少量的信息和对该资源所执行的操作来表征该资源,所以共享系统资源就变为了共享数据结构,并将对这些共享数据结构的操作定义为一组过程。进程对共享资源的申请、释放和其他操作必须通过这组过程。代表共享资源的数据结构以及由对该共享数据结构实施操作的一组过程所组成的资源管理程序共同构成了一个操作系统的资源管理模块,我们称之为管程;

    管程由四部分组成:名称、局部于管程的共享数据结构说明、对该数据结构进行操作的一组过程、对局部于管程的共享数据结构设置初始值的语句;

    所有进程访问临界资源时,都只能通过管程间接访问,而管程每次只准许一个进程进入管程,从而实现互斥。管程体现了面向对象程序设计的思想;具有:模块化,即管程是一个独立的基本单位,可单独编译;抽象数据类型,不仅有数据还有对数据的操作;信息隐蔽,管程中的数据结构只能被管程中的过程访问,这些过程也是在管程内部定义的,而管程之外的进程只需调用而无需了解其内部的具体实现细节。(这样,原来遍布系统的共享资源的访问代码,就集中到管程中啦);

    管程和进程的对比(两个截然不同的概念,有什么好对比的呢?大概是名字相似吧)

    1. 两者都定义了各自的数据结构,但是管程定义的数据结构是对公用资源的抽象,进程定义的是私有数据结构PCB;
    2. 两者都有对各自数据结构的操作,但是管程的操作是为了实现同步和初始化,进程是由顺序程序执行有关操作;
    3. 进程的目的是在于实现系统的并发,而管程的目的是解决共享资源的互斥访问;
    4. 进程是主动工作的,管程需要被其他程序使用,属于被动工作的;
    5. 进程有动态性,管程是操作系统中的一个资源管理模块;

    管程中还有一个比较重要的概念就是条件变量。当一个进程进入了管程但在管程中被阻塞或者挂起,此时该进程需要释放对管程的占有,并且根据阻塞或者挂起的原因,也就是条件变量,进入相应的等待队列,等待其他进程的唤醒。条件变量x具有两种操作:x.wait()和x.signal();

    x.wait():正在调用管程的进程因x条件而需要被挂起或者阻塞,则调用x.wait()将自己插入到条件变量x的等待队列上并释放管程,直到x条件变化;

    x.signal():正在调用管程的进程发现x条件发生了变化,重新启动一个因x而阻塞的进程,如果有多个进程因x而阻塞,也只能选择一个;

    如果进程Q因为x条件而处于阻塞状态,当P调用管程时,执行了x.signal()操作后,Q重新启动,此时P和Q到底谁来继续拥有管程呢?答案是两者均可;

    经典的进程同步问题

    这里只列出问题,不做具体介绍和分析,关于进程同步,其实更多的是线程同步,有一本很棒的书《图解Java多线程设计模式》,这本书讲解了12种如何利用多线程来编程的方法,每一种方法作者将其称为一种模式,其中就有下面提到的问题的解决方案。这十二种方法讲解了到底该如何安全地使用多线程(即考虑到线程的同步问题)

    1. 生产者-消费者问题;
    2. 哲学家进餐问题;
    3. 读-写问题;

    进程通信

    在进程之间要传送大量数据时,应当利用OS提供的高级通讯工具,该工具的特点是:

    1. 使用方便:OS隐藏了实现进程通信的细节,向用户提供一组用于实现高级通信的命令(原语),即通信过程是对用户是透明的;
    2. 高效传输大量数据:用户可以直接利用高级通信命令传输大量的数据;

    进程通信的类别

    高级通信机制分为四类:共享存储器、管道通信系统、消息传递系统以及客户机-服务器系统;

    共享存储器系统

    相互通信的进程通过共享某些数据结构或者共享存储区,进城之间通过这些空间实现通信;常见的有基于共享数据结构的通信方式和基于共享存储区的通信方式;

    1. 基于共享数据结构的通信方式

      通信进程共用某些数据结构来实行进程之间的信息交换。操作系统仅提供共享存储器,由程序员负责对公用数据结构的设置以及进程间同步的处理;这种方式仅适用于传输数据量少的情况下,通信效率低,属于低级通信;

    2. 基于共享存储区的通信方式

      为了传输大量数据,在内存中划出一块共享存储区域,各个进程通过对该共享区的读或者写交换信息,从而实现通信;数据的形式和位置甚至访问方式都是由进程负责。这种通信方式属于高级通信;需要通信的进程首先向系统申请获得共享存储区的一个分区,将其添加到自己的地址空间,当通信结束后,再将此区域归还系统;

    管道通信系统

    管道,是指用于连接一个读进程和一个写进程以实现他们之间通讯的一个共享文件,有名pipe文件;写进程将信息以字符流的形式送入管道;而读进程将从管道中接受数据。由于通信双方通过管道文件通信,所以这种通信方式也称为管道通信;管道通信需要解决三个问题:

    1. 互斥:对管道文件的访问需要互斥进行,写进程和读进程不能同时对pipe文件操作;
    2. 同步:写进程不能无限对pipe文件写入,通常,当写入一定量的信息后,写进程就会睡眠,直到读进程读取了信息后再唤醒写进程;
    3. 确定对方是否存在:只有确定对方已存在时才能进行通信,否则,只有写进程的话,就没有进程把它唤醒;而只有读进程的话,由于没有内容,所以它可能一直等待而无法执行其他代码;

    消息传递系统

    在该机制中,进程不必借助任何共享存储区或者数据结构即可实现通信,它以格式化的消息为单位,将信息封装在消息中,利用操作系统提供的消息发送原语,在进程之间实现消息传递,完成数据交换;

    该通信方式隐藏了通信细节,使通信过程对用户透明化,降低了通信程序设计的复杂性和错误率,成为当前应用最为广泛的一种进程同信机制;由于该机制能很好支持多处理机系统、分布式系统和计算机网络,因此也成为这些领域中最主要的通信工具;

    基于消息传递系统的进程间通信属于高级通信方式,按照其实现方式的不同,进一步分为:直接通信方式和间接通信方式;其中直接通信方式使用操作系统提供的原语操作,直接将信息发送到接受进程;间接通信方式通过共享中间实体(被称为邮箱)来实现进程间通信;

    在直接通信方式中,存在两种寻址方式,一种是对称寻址方式,另一种是非对称寻址方式;

    对称寻址方式中,接收方需要明确指出发送方的标记,发送方需要明确指出接收方的标记,问题就是一旦某个进程改变了该标记,所有与其有通信的进程都需要做出改变,不利于实现进程定义的模块化;

    非对称寻址方式中,接收方不需要明确指出发送方的标记,只需填写表示原进程的标记,但是发送方需要指出接收方的标记;

    发送进程和接受进程之间要能通行,就需要建立通信链路。有两种方式建立通信链路,一种是发送进程在通信前显式调用“建立连接”命令请求系统为之建立一条通信链路;链路在使用完毕后拆除,这种方式主要用于计算机网络中;另一种是,发送进程无需显式提出建立链路的请求,由系统自动为之建立一条链路;这种方式主要用于单机系统中;

    而根据通行方式的不同,链路又可以分为:单向链路和双向链路;单向链路只允许发送进程向接收进程发送消息,不允许接收进程向发送进程发送消息;双向进程则可以实现双向通信;

    关于信箱通信:

    信箱被定义为一种数据结构,每个信箱都有一个唯一的标识符,消息在邮箱种可以安全地存取,只有被核准的目标用户才能随时读取;

    信箱的结构逻辑上包含:

    1. 信箱头,由于存放关于信箱的描述信息,如信箱ID,信箱的拥有者,信箱口令,信箱的空格数等;
    2. 信箱体,由若干个可以存放消息的信箱格组成;

    信箱的类型包括:

    1. 私用邮箱:由用户进程创建,只有邮箱的拥有者才能从邮箱里读取消息,其他进程只能向该邮箱发送消息;当拥有该邮箱的进程消失时,邮箱也就消失了;
    2. 公用邮箱:由操作系统创建,供给系统中的所有核准进程使用,核准进程既可以把消息发送到该邮箱也可以从该邮箱里读取信息。通常,公用邮箱在系统运行期间一直存在;
    3. 共享邮箱:由某进程创建,所有共享该邮箱的进程都可以取走该邮箱中自己的邮件;其实算得上是小范围里的公用邮箱吧;

    客户机-服务器系统

    前面三种方式,共享存储区域、管道、消息传递系统也可以实现不同计算机进程之间的双向通信,但客户机-服务器系统的通信机制在网络环境中的各种应用领域已成为主流的通信实现方式;其主要有两类:套接字、远程过程调用或远程方法调用;

    1. 套接字

      套接字来源于Unix操作系统,被设计用于同一台主机上的多个应用程序之间的通信,主要是为了解决多对进程同时通信时端口和物理线路的多路复用问题。

      一个套接字就是一个通信标记类型的数据结构,包含通信的目的地址、通信使用的端口号、通信网络的传输层协议、进程所在的网络地址,以及针对客户或者服务器程序提供的不同系统调用等,是进程通信和网络通信的基本构件。套接字为客户机-服务器模式而设计,主要分为基于文件的和基于网络的两种;

      1. 基于文件:通信进程位于同一台主机,套接字基于本地文件系统支持,一个套接字关联一个特殊的文件,通信进程通过该文件实现通信,类似管道通信;
      2. 基于网络:通信进程位于不同主机的网络环境下,通常采用非对称方式通信。通信的发起者需要提供接受者的命名;发送进程提出连接请求时,随机申请一个套接字,主机将为之分配一个端口与该套接字绑定。接受进程通过监听端口等待客户的请求,一旦收到请求,就接受连接,实现进程之间的通信;当通信结束后系统通过关闭接受进程的套接字来撤销连接;

      套接字的优势在于,不但可以用于本地计算机内部的进程通信,还适用于网络环境中的不同计算机间的进程通信。每一个套接字都拥有一个唯一的套接字号,这样系统中所有的连接都持有唯一的一对套接字及其端口连接,可以方便地区分来自不同应用程序进程的连接通信,确保了通信双方之间逻辑链路的唯一性,便于实现数据传输的并发服务,还隐藏了通信设施及其实现细节;

    2. 远程过程调用或远程方法调用

      远程过程调用RPC是一个通信协议,适用于通过网络连接的系统。该协议允许运行于一台主机系统(本地)上的进程调用另一台主机(远程)上的进程,对程序员表现为一般过程调用。在面向对象程序设计当中,这也称之为远程方法调用;

      负责处理远程过程调用的进程有两个,一个是本地客户进程,另一个是远程服务器进程,这两个进程通常也称为网络守护进程,负责网络间的消息传递;

      为了实现RPC的透明性,使得调用者感受不到此次调用的过程发生在其他主机上,RPC引入存根的概念:在本地客户端,每个能够独立运行的远程过程都对应一个客户存根,本地进程调用远程过程的实际是调用该过程所关联的存根。与此类似,每个远程进程所在的服务器端,其所对应的实际可执行进程也关联一个服务器存根。本地客户端存根于对应的服务器存根一般也是出于阻塞状态,等待消息;

      客户端发起RPC的主要步骤是:

      1. 本地过程调用者A以一般形式调用远程过程B在本地关联的客户存根CStub,传递参数并将控制权交给CStub;
      2. CStub完成包括过程名、调用参数等信息的消息的简历,将控制权交给本地客户进程;
      3. 本地客户进程完成与服务器的消息传递,将消息发送到远程服务器进程;
      4. 远程服务器进程接收到消息后,根据其中的过程名找到服务器存根SStub,将消息转交给SStub;
      5. SStub接收到消息后,从阻塞状态转入执行,从消息中取出过程调用的参数,然后调用与之关联的服务器进程;
      6. 服务器进程运行完毕后将结果返回给服务器存根SStub;
      7. SStub将结果打包为消息,将控制权转交给远程服务器进程;
      8. 远程服务器进程将消息发回客户端;
      9. 本地客户进程接收到消息后,根据其中的过程名找到与之关联的客户端存根CStub,将控制权和消息交给CStub;
      10. CStub从消息中取出结果,然后将其返回给本地调用者A,完成控制权的转移;
      11. 结束
    展开全文
  • 2.3 进程同步

    2020-10-16 20:43:08
    2.3.1 进程同步的基本概念 多道程序环境下,进程是并发执行的,不同进程之间存在着不同的制约关系。为了协调进程之间的相互制约关系,引入进程同步的基本概念。 异步性:各并发执行的进程以各自独立的,不可预知的...

    2.3.1 进程同步的基本概念

    多道程序环境下,进程是并发执行的,不同进程之间存在着不同的制约关系。为了协调进程之间的相互制约关系,引入进程同步的基本概念。
    异步性:各并发执行的进程以各自独立的,不可预知的速度向前推进。


    1.临界资源

    许多资源只能为一个进程所用,我们将一次仅允许一个进程使用的资源称为临界资源
    对临界资源的访问必须 互斥 进行
    访问临界资源的代码叫做 临界区

    2.同步

    同步亦称直接制约关系是指多个进程中发生的事件存在某种先后顺序

    3.互斥
    互斥也称间接制约关系是指多个进程不允许使用同一 临界资源


    为了禁止两个进程同时进入临界区,同步机制应遵循以下原则:
    1)空闲让进
    2)忙则等待
    3)有限等待
    4)让权等待 当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。

    2.3.2 实现临界区互斥的基本方法


    一、软件实现方法
    1)算法一 :单标志法
    违背 空闲让进 设置变量 turn,turn=0允许P0进入,turn=1允许P1进入。若P0顺利离开,此时临界区空闲,但是P1没有进入临界区的打算,turn=1就一直成立,其他进程无法进入。
    在这里插入图片描述

    2)算法二 :双标志法先检查

    每个进程在访问临界区之前,先查看临界资源是否正在被访问。为此设置一个数据flag[i],如第i个元素值为FALSE,表示进程Pi未进入临界区,TRUE为进入临界区。
    在这里插入图片描述
    优点: 不用交替进入,可连续使用
    缺点: 若按照①②③④顺序执行,两个进程会同时进入临界区违背 忙则等待 原则

    3)算法三 :双标志法后检查

    算法二先检查对方的进程状态,在设置自己的标志,会造成两个进程同时进入临界区。
    为此算法三先将标志位设为TRUE,再检测对方标志,若对方为TRUE则进程等待,否则进入
    在这里插入图片描述
    两个进程几乎同时都想进入临界区时,他们分别将自己的标志位flag设为TRUE并检测对方flag,发现对方也要进入,则导致两个进程都不进入临界区。

    导致饥饿现象

    4)算法四 :Peterson’s Algorithm

    为了防止两个进程无限期的等待,设置变量turn,每个进程先设置自己的flag标志再设置自己的turn标志turn表示谦让,flag表示意愿

    在这里插入图片描述
    在这里插入图片描述
    不遵循 “让权等待原则”会发生忙等


    二、硬件实现方法

    1)中断屏蔽法
    防止其他进程进入临界区进行访问的最简单方法是禁止一切中断发生,或称之为屏蔽中断、关中断

    在这里插入图片描述
    只适用于单处理系统(操作系统内核)


    2)硬件指令方法

    TestAndSet指令:这条指令是原子操作,执行该代码不允许被中断

    bool TSL(bool *lock){
    bool old;
    old = *lock;
    *lock=true;
    return old;
    }
    while(TSL(&lock));
    //临界区代码段
    lock = false;
    //剩余区代码段
    

    不满足让权等待原则

    Swap指令:也不满足让权等待原则

    展开全文
  • 进程同步与进程互斥

    2020-02-18 18:35:39
    (1)什么是进程同步 (2)什么是进程互斥 2.什么是进程同步 进程具有异步性的特征。异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。 再看另一个例子:进程通信--------管道通信 读进程和写...
  • 进程互斥与进程同步

    2017-09-07 21:45:43
    进程之间的相互作用关系分为两种,一种是共享资源的关系,一种是相互合作的关系,前者属于进程互斥、后者属于进程同步。我们把实现这两类相互制约关系的机制,统称为进程同步机制。同步机制有四大原则:空闲让进、忙...
  • 进程同步的任务就是对多个相关进程在执行次序上进行协调,使得并发执行的进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。
  • 进程同步是指对多个相关进程在执行次序上进行协调,以使并发执行的主进程之间有 效地共享资源和相互合作,从而使程序的执行具有可在现行。 首先,程序在调用fork()机那里了一个子进程后,马上调用wait(),使父进程...
  • 进程同步和互斥

    万次阅读 多人点赞 2018-10-01 09:18:20
    2.9 进程同步的基本概念:临界资源、同步和互斥 在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。为了协调进程之间的相互制约关系,引入了进程同步的概念。 临界资源 虽然多个进程...
  • 进程同步or进程通信/线程同步or线程通信? 这两组概念迷惑我至今,网上和书籍对这个的描述也是爱用啥用啥的感觉,今天又重新理了一遍。 什么是同步:同步就是数据保持一致,无论是进程还是线程,都是实现了代码执行...
  • 进程同步的主要任务: 进程两种形式的制约关系: 临界资源: 最常见的临界资源:打印机,磁带机等机械硬件设备,在一段时间内只能给某个进程使用! 消费者生产者关系高级语言伪码:(看似是对的!)...
  • 进程同步实例

    千次阅读 2017-12-07 11:30:24
    有时候父进程要求子进程的运算结果进行下一步的运算,或者子进程的功能是为父进程提供下一步执行的先决条件,此时... 下面就是父子进程同步的一个实例,子进程进行写操作,父进程读出子进程写的内容#include #include
  • 进程同步的概念临界资源:许多硬件资源如打印机、磁带机等,都属于临界资源(CriticalResouce) 临界区:人们把在每个进程中访问临界资源的那段代码称为临界区(critical section) repeat entry section critical ...
  • 进程同步,进程锁

    千次阅读 2014-08-15 16:44:06
    1. 进程同步方式
  • 进程同步/异步

    2018-10-13 00:38:34
    进程同步:这是进程间的一种运行关系。“同”是协同,按照一定的顺序协同进行(有序进行),而不是同时。即一组进程为了协调其推进速度,在某些地方需要相互等待或者唤醒,这种进程间的相互制约就被称作是进程同步。...
  • 文章目录进程同步临界资源临界区同步和互斥信号量互斥量经典进程同步问题生产者消费者问题读者写者问题进程通信匿名管道通信命名管道通信(FIFO)信号信号量共享存储套接字消息队列 进程同步 临界资源 一次仅允许一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,181
精华内容 13,272
关键字:

进程同步