青春无悔
分类: C/C++
2015-03-08 22:51:36
所谓原子操作,并不是指一条指令,而是指一系列操作不能被打断.
这种操作与临界区是密切相关的,可以说原子操作就是临界区引发出来的需求.
以上是给大家提供资料查找的入口,下面我用通俗的话说说,但切不要认为自已看懂了就可以不去查以上相关资料了,知道啥叫"通俗"吗?呵呵.废话不多说:
在多进程的系统里(比如多任务,比如中断服务程序),假如两组程序都要访问同一个资源,而作为程序员的你没有办法避免在一个进程访问完该资源之前,另一进程就来访问该资源,就出现了访问冲突,这就是临界区问题.
举个实际例子:假如A进程用变量a作为临时存储区时,如果运行到一半中断发生了,而中断里也会用到该变量,等中断返回时,变量a中的内容已经被破坏了,进程A并不知道这一点,于是得到错误的运行结果.
避免的办法看似简单:拿个变量来当标志,为0时表示没人用共享资源,为1时表示正在使用.使用时先检查该标志,为1时等待,为0时则置1,并使用资源,用完后将标志置回0,于是资源冲突问题就解决了.
是吗?问题转移了----当你检查完变量,发现它为0,正要将它置1时,此时进程被打断,于是别的进程仍会毫不客气的使用该资源,要命的是在多任务系统中,当CPU控制权回来时,刚才使用这个资源的进程还没用完这个资源呢,于是出错了.
可以看出来,必须有一种这样的指令:先检查某变量,当它为0时则置1并跳转,而这一系列过程不允许被打断,拥有这种能力的指令就叫作"原子操作指令".由于51没有这种指令,这也就是为什么楼上很多人说要关中断的原因了.事实上,关中断这种方式也用于我们桌面机系统!LINUX就用了很多关中断.
虽然51没有上面说的这种指令,却有另一个指令:DJNZ---先减再检查,并根据比较结果跳转,而这足够完成临界区操作了.
系统初始化是必须事先将s置初值为1
aqui_mutex:
DJNZ s, wait
....共享资源操作代码(也就是临界区)
INC s
RET
wait:
INC s
jmp aqui_mutex
以上代码在任何情况下(跑飞不算,呵呵)不会发生两个进程同时进入临界区的情况.
你一定会想到,假如将上面的代码写成一个子程序,那就可以作为一个标准函数供C调用了,恭喜你,这就是标准的信号量.
关于"临界区","信号量","原子操作",这些词和概念都是操作系统里整天要讨论的东西,而没接触过操作系统的人很难想到困扰自已的问题原来早就有人已经作出了系统的描述并找到解决的方法了,所以说,并不是"用不上"的知识就可以不学,知识是有关联性的,更高级的系统往往也会有更高级的思想.你未必需要穿皮鞋,但你必须了解皮鞋跟草鞋的区别和各自的优缺点