概念
共享内存在通信的过程中,没有任何保护机制。当A进程写入了一部分,就被B、拿走了,导致双方发和收的数据不完整,数据不一致问题
1.A和B看到同一份资源,共享资源,如果不加保护,会导致数据不一致问题
2.加锁–互斥访问,任何时刻,只允许一个执行流访问共享资源叫互斥,如ITM机,只允许一个人操作,结束后另一个人才可以操作
3.共享的,任何时刻只允许一个执行流访问代码的资源,叫临界资源,一般是内存空间
4.很多代码中只有几行代码访问临界资源,访问临界资源的代码叫临界区
在一个多进程或多线程并发打印的情况,显示器上的消息可能是1.错乱的 2.混乱的 3.和命令行混在一起,这种情况就是正常现象
原理
信号量类似一个计数器,描述临界资源中资源数量的多少
一个例子,电影院买票,将100个座位看做100个资源,买票的本质就是对资源的预定,电影播放时这个座位就属于自己。有一个票数的计数器等于100,每卖出一张票,计数器–,当计数器到0时,就不能再卖了,就是资源已经申请完
关于临界资源害怕的问题:
1.多个执行流访问同一个资源
2.共有n个资源,但有n+个执行流
第一种情况的解决方法是代码的逻辑问题。如果有多个执行流,可以将临界资源分为几块,让每个执行流访问其中的一块区域。第二个解决办法就是可以给这些资源引入一个计数器,数量表示当前有多少个资源,当申请一个资源时计数器–,如果为0的时候,表示没有资源了,再申请的时候就不给了,就不会出现执行流比资源数量多的情况
总结
1.申请计数器成功,就表示具有访问资源的权限了
2.申请了计数器,当前没有访问资源,只是对资源的预定机制
3.计数器可以有效保证进入共享资源的执行流的数量
4.所以每一个执行流,想访问共享资源的一部分的时候,不是直接访问,而是先申请计数器资源
将这个计数器称为信号量
如果电影院只有一个座位,就只需要一个值为1的计数器,只有一个人能抢到,一个人能看电影,就是只有一个执行流可以访问临界资源,申请了计数器就变为0。把这种值为1和0的计数器叫做二元信号量,本质就是一个锁
计数器为1的本质就是临界资源当成一个整体,整体申请,整体释放
保证计数器安全
计数器也是共享资源吗?计数器保护临界资源有效,得先保证自己安全。对计数器的操作是–,这个操作不是安全的
–操作在汇编中有三条语句以上
1.cnt变量的内容,拷贝到cpu寄存器
2.cpu内进行–操作
3.将计算结果写回cnt变量的位置
cpu内的进程是随时切换的,就可能在执行上面某一条的时候就被切换了
PV
操作系统内部对计数器进行了封装,申请信号量,将计数器–,作为P操作
释放资源,释放信号量,对计数器++,作为V操作
申请和释放这种PV操作,让它是原子的
原子的:要么不做,要么就做完,两态的,没有“正在做”这样的概念
这样就保证了计数器的安全
信号量本质是一把计数器,PV操作,原子的,执行流申请资源,必须先申请信号量资源,得到信号量后才能访问临界资源
信号量1,0两态的,二元信号量,就是互斥功能
申请信号量的本质:对临界资源的预定机制
函数
申请信号量,可以是多个,nsems参数控制
释放信号量,semum填0表示只有一个信号量,用下标0。否则,需要自己设置结构体
信号量为什么是通信
前面的通信都是可以互相发送消息,而信号量只是一个计数器,为什么也是通信的一种
1.通信不仅仅是通信数据,互相协同也是,信号量协助资源的安全
2.要协同,本质也是通信,信号量首先要被所有的通信进程看到
补充
mmap函数,也是共享内存的一种
共享内存是在内存中申请一块地址映射到虚拟内存中,通过虚拟内存访问这块资源,如果申请的内存不是从内存中,而是一个磁盘文件的地址映射。就可以直接读写文件,不需要read,write这些函数,直接对地址操作。这个就是mmap函数