1. 基于对共享内存的理解
为了让进程间通讯,我们让不同的进程看到了同一份资源。我们之前所写的通信方式,本质上都是优先解决一个问题:让不同的进程看到同一份资源。
让不同的进程看到同一份资源也带来一些问题,比如共享内存就有时序性问题。
接下来引入概念:
- 临界资源:我们把多个进程(执行流)看到的公共的一份资源称为临界资源。
- 临界区:我们把自己的进程,访问临界资源的代码称为临界区。
- 互斥:为了更好的进行临界区的保护,可以让多执行流在任何时刻,都只能有一个进程进入临界区,这种行为称为互斥。
- 原子性:要么不做,要么做完,没有中间状态,称之为原子性。
所以多个执行流,互相运行时互相干扰的主要原因是我们不加保护的访问了同样的资源(临界资源),在非临界区多个执行流互相是不影响的。
2. 信号量的理解
每一个进程想进入临界资源,访问临界资源中的一部分,不能让进程直接去使用,需要先申请信号量(买电影票)。信号量可以不准确的理解成计数器。
申请信号量:
申请信号量的本质就是让信号计数器--。
申请信号量成功,临界资源内部一定预留好了需要的资源。申请信号量本质其实是对临界资源的一种预定机制。
访问临界资源,进程执行自己的临界区代码
最后释放信号量,++。
原子性的理解:
数据的计算需要在CPU内,而数据在内存中。
CPU执行指令的时候有三个步骤:1.将内存的数据加载到CPU的寄存器中(读指令)2.分析并执行指令3.将执行完的结果数据重新写回内存。
由于
1.执行流在执行时,在任何时候都可能被切换。
2.cpu的寄存器只有一套,被所有资源共享,但是寄存器里面的数据,属于每一个执行流,属于该执行流的上下文数据。
如果两个进程(a和b)同时申请信号量。a进程在CPU执行第二步时被切换,仍然拿着未修改的数据(假设是5)和要执行的步骤进行阻塞。此时B进程执行,拿到的数据是5,--,将4放回内存。然后进程a执行,此时依然是拿这未修改的数字5,然后进行--,再讲4放回内存覆盖原来的4。这样的话我们的信号量就少减了一次。
结论
信号量计数器是对临界资源的预定机制。
申请信号量-> 计数器-- ->P操作 ->具有原子性
释放信号量->计数器++ ->V操作 ->具有原子性