前言
以<深入理解计算机系统>(以下称“本书”)内容为基础,对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定
引入
接续理解计算机系统_并发编程(6)_线程(三):线程内存模型和同步问题-CSDN博客,上贴提到了同步问题,这里将用信号量解决同步问题.
信号量概念及描述
本书原话:这种方法是基于一种叫做信号量的特殊类型变量的.信号量s是具有非负整数值的全局变量.
---解读:概念的阐述中常有"这是什么什么类型".信号量类型如下所示
typedef sem_t unsigned int; //非负整型定义
PV操作的过程
首先本书这块写得挺乱,让人十分费解(不知道是故意翻译得很差还是怎么回事),笔者尝试以时间线穿插概念的形式来理解PV操作.
1.s是信号量,非负整数.
---注意:不管什么情况下,s≥0.
2.P(s)操作.
a.如果s!=0,则s=s-1并返回.
b.如果s==0,则调用P(s)操作的当前线程(假设为A)被挂起(注意:此时s不等于-1,仍等于0).这时需要一个V操作来重启被挂起的线程---如果一直没有V操作,有多个线程(如B,C,D)进行P操作,则他们都将被挂起(被阻挡)
当执行完等待的V操作后,s=1,前面被阻挡的一个线程(假设为A)被重启,再回去执行P操作(刚才线程挂起,P操作并未进行.)将s-1后s=0.线程A得以执行P(s)后的代码,访问共享数据.而其他被阻挡的线程仍被阻挡,直到下一个V操作的到来,重启他们其中的一个.
3.V(s)操作
将s加1,即s=s+1;
如果s=0,线程处于阻塞(或挂机)状态,则操作后s=1并且重启一个被挂机的线程.
PV操作的特点
1.原子性.
P(s)和V(s)都是不可分割的,中间没有停顿
2.V(s)操作不能确定重启哪一个线程.
本书原话:当有多个线程在等待同一个信号量时,你不能预测V操作要重启哪一个线程.
---解读:可能有多个线程调用P(s)---尝试访问共享数据,仍没有进行V(s)操作,这时s仍等于0,并且这些线程都处于挂起状态.再进行V(s)操作,可以重启其中一个线程,但不能确定到底是哪个.
3.信号量不变性.
本书原话:P和V的定义确保了一个正在运行的程序绝不可能进入这样一种状态,也就是一个正确初始化了的信号量有一个负值.
---解读:前面说了,不论什么情况下,s≥0.由这一点控制了并发
=============================内容分割线↓===================================
一句话概括信号量:解决了同步问题.任何时刻只能有一个线程访问共享变量.
=============================内容分割线↑===================================
信号量实现互斥
关于进度图,笔者选择跳过(原理复杂,代码简单可以选择性忽略)
理解了信号量的工作原理,互斥也容易理解:P操作是信号量加锁,V操作是信号量解锁.代码
//信号量互斥的代码
volatile long cnt=0;
sem_t mutex;
Sem_init(&mutex,0,1); //初始化信号变量,mutex被赋值为1
for(int i=0;i<niters;i++){
P(&mutex); //加互斥锁
cnt++; //操作共享数据
V(&mutex); //解互斥锁
}
小结
信号量的概念以及信号量实现互斥

1348

被折叠的 条评论
为什么被折叠?



