进程同步

1. 进程同步

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

2. 信号量

2.1 信号量描述
由一个整形变量(sem)和两个原子操作组成。sem表示共享资源的数量。
两个原子操作为:
P(): sem减1,如sem<0,进入等待,否则继续 。(申请资源);
V(): sem加1,如sem<=0,唤醒一个等待进程 (释放资源)
信号量是被保护的的整数变量,初始化完成后,只能通过P()和V()操作修改。P、V操作是原子操作。P()可能阻塞,V()不会阻塞,它可以请处于阻塞的线程转换为就绪状态。
2.2 信号量实现

classSemaphore{
    int sem;
    WaitQueue q;
}
Semaphore::P(){   
    sem--;
    if(sem<0){               //减1和判断是原子的,原子性由操作系统保证
    Add this thread t to q;  //将当前线程放入等待队列
    block(t);                //将当前线程由就绪状态转换为等待状态
 }
}
Semaphore::V(){
    sem++;
    if(sem<=0){              //加1和判断是原子的,原子性由操作系统保证
    Remove a thead t from q; //把线程从等待队列中放到就绪队列里 
    wakeup(t);               //把线程由等待状态转换为就绪状态               
  }
}

2.3 信号量分类
二进制信号量:资源数目为0或1,可用于保证n个过程是互斥的,用于对共享变量的互斥访问。
计数信号量:资源数目初始化为0或任何非负值,表示系统可用资源的数量,可用于条件同步。
例子:
互斥访问:用一个信号量来对应一个临界区,任何一个临界区在任何一个时刻只允许一个线程执行临界区的代码。信号量的初值设置为1

mutex = new Semaphore(1);
mutex->P();
Critical Section;
mutex->V();

条件同步:线程间的事件等待
假如线程A要等待线程B执行操作B1后才能进行操作A1。做法: 设置一个信号量,初始化为0,表示没有事件B1发生。

condition = new Semaphore(0);   //初始
//线程A
...  
condition->p(); 
A1(); 

//线程B
...
B1();
condition->V();
...

2.4 信号量的必要性
互斥机制只能允许一个线程同一时刻进入临界区,而有的时候允许多个线程同时进入临界区比如读写问题中多个读操作的线程;有的时候需要在某种条件满足下才能进入临界区,比如生产者在有空的buffer才能生产。

3. 管程(互斥锁和条件标量)

3. 1 引入目的
使用信号量设计一个正确的程序是很困难的,操作不当可能造成死锁。管程提供了与信号量同样的功能,但更易于控制。它的好处是将互斥和条件同步进行了分离。
3.2 管程组成
管程由一个锁、0个或多个条件变量组成,1个或多个过程组成。这n个过程会访问共享变量。
锁:管程使用锁保证了这n个过程对共享变量的互斥访问。
条件变量:保证n个过程是同步的。使用时,通过互斥锁进入管程代码访问共享变量,当发现条件不满足时,线程解开相应的互斥锁并等待条件发生变化.一旦其他的某个线程发现条件满足就改变条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程.这些线程将重新锁定互斥锁并重新测试条件是否满足。
条件变量有两个操作:Wait和Signal。
Wait()操作: 如果条件不满足,将自己阻塞在等待队列中,并释放管程的互斥访问;如果条件满足并Signal调用后,等待在该条件变量的一个线程会唤醒,并重新获得互斥锁并返回。
Signal()操作:将等待队列中的一个线程唤醒,如果等待队列为空,则等同空操作
3.3 条件变量实现

Class Condition{
    int numWaiting = 0;  //信号量的初值等于资源数,而Condition初值为0,表示等待该条件变量的线程数目。
    WaitQueue q;        //等待队列,等待条件变量的线程都放到等待队列中 
}
Condition::Wait(lock){
    numWaiting++;   
    Add this thread t to q;   //将当前线程放到等待队列中,线程从运行状态进入阻塞状态
    release(lock);            //释放管程的互斥访问权
    schedule();               //执行cpu调度,cpu开始从就绪队列中找出一个线程开始执行
    require(lock);            //signal后,线程开始运行,请求管程的互斥访问权
}
Condition::Signal(){
    if(numWaiting>0){
        Remove a thread t from q;  //把线程从等待队列中移出
        wakeup(t);                 //把线程放到就绪队列里,线程从就绪状态变成就绪状态
        numWaiting--;
        }           
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值