【并发编程】-- 并发控制原理-PV原子性、信号量、互斥量

541 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

并发控制原理

P-V原语

原语就是原子语义,P-V减和加两个操作具有原子性,即全部执行完成或都不执行,并且在执行过程中只能有一个线程进入执行,那为什么需要原子语义的操作呢?这涉及到并发与并行操作,就是上述一个变量加1不做原子性操作可能发生的情况。

P-V原语是P和V操作具有线程安全性,即原子性,可以查看以下伪代码:

int num = 0;
add(){
	num = num +1;
}
subtract(){
	num= num - 1;
}

简单而言就是对一个变量进行增加或减少,以保证线程安全性的操作就称为P-V原语。

信号量

信号量是依赖于P-V原语来构建的一套线程安全机制,就是给定一个初始资源数n,然后利用P-V原语对n进行操作,当n大于或等于0时,任务获得资源执行,当n小于0时,对任务进行阻塞。

具体实现伪代码如下:

int num = 0;
Queue queue;
p(){ //原子性操作
    if(count <0){ //当资源数小于0时表明没有足够资源,那么去队列阻塞
        queue.add(Thread);
        while(count < 0) wait;
    }
    num = num - 1;
}
v(){ 	//原子性操作
    num =num +1; 
    if(num > 0 && queue.isNotEmpty()){ //当资源数大于0并且队列不为空时,唤醒等待资源的任务
        Task task= queue.remove();
        Notify task;
    }
}

上述代码就是信号量的核心代码,信号量就是利用P-V原语对num变量操作,然后配合一个等待队列进行任务阻塞。

互斥量

互斥量就是信号量的特殊版本,信号量有多个资源,互斥量则有且只有一个资源,就是信号量为1的特殊情况,但是,它们之间也有所不同。

代码如下:

ConditionVariables conditionVariables;
Thread a(){
    while(!conditionVariables){
       wait();
    }
}
Thread b(){
     while(!conditionVariables){
       wait();
    }
}

初始化一个条件变量,当条件不满足时,所有任务都阻塞等待,直到条件变量满足条件后,唤醒所有等待任务。注意点是这里唤醒是所有任务,而不是唤醒一个,这也是与信号量不同的点,信号量是用P-V原语对一个num增加或减少来唤醒任务或者阻塞任务。