信号量的通俗解释

参考:https://blog.csdn.net/ljianhui/article/details/10243617

信号量的工作原理
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
注:上面的 P(sv)的描述等价于:sv减一,如果减完后>=0,则进程继续执行,如果减完后<0,就挂起该进程的执行

举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

注:什么叫“进入临界区”?

举个应用例子:有多个进程要通过串口向外打印调试信息,串口的读写速度相比于内存的读写速度来说,显然是过慢了,所以,输出调试信息时,肯定是把信息写入到串口缓冲区内存,然后串口不慌不忙的把缓冲区的数据一点一点的发出去,那么问题来了,如果多进程并发,进程A要发abc,进程B要发123····,同时向缓冲区写数据,那么缓冲区的数据就不一定是abc123了,很有可能会乱套,如a1bc23、a1b2c3等,为了解决这一问题,就引出了“临界操作”这一概念,也就是说,一旦某进程A开始写缓冲区了,那么任何其他进程BCDE···都不得写该缓冲区,而是进入等待/阻塞状态,直到进程A写完了,BCDE···中的一个才能继续写入,这样进程A的写入操作就被保护起来了,A的写缓冲区的代码就是一段临界代码。

上述过程的伪代码如下:

sv=1;

每个进程的write_to_serial_buf()都被临界保护了,任何时刻都只有一个进程能向串口发数据,其余进程要么在执行其余代码,要么被卡在p(sv)语句上等待.

p(sv)和V(sv)用伪代码可以这样写:

void P(int &sv)
{
    sv--;
    while(1)
    {
        if(sv < 0)
            堵塞本进程;
        else
            break;
    }
}

void V(int &sv)
{
    sv++;
}
当然,真正的P/V函数肯定不是这样写的,仅仅为了说明原理,P函数不可能用while来等待SV>=0,而是阻塞进程等待解除信号,V函数不可能仅做sv++,还得发信号


猜你喜欢

转载自blog.csdn.net/qq_31073871/article/details/80543549