临界区操作的原子性

来源:互联网 发布:即时通讯软件 编辑:程序博客网 时间:2024/05/22 17:56

所谓的原子性就是操作在未执行完之前不会被打断,在多线程变成的时候,很多时候都会在线程函数中或者被线程调用的函数中使用临界区来实现函数操作的原子性。

临界区保证当前进入临界区的线程能够完整执行完临界区中保护的代码不被打断,但是当时我一直对临界区有一个疑问,即临界区自己的代码中如何实现这种特性,也就是一个线程调用调用进入临界区的函数,这个函数EnterCriticalSection如何保证自己的代码不被打断,因为只要存在线程调度,那么每个线程都可能随时被打断,保存,然后内核重新调度接下去要运行的线程,如果A,B两个线程都是进入函数Proc,Proc开头的EnterCriticalSection函数如何保证自己不会受到线程调度的影响。

例如线程A先执行了EnterCriticalSection函数的一部分,然后系统发生定时中断,接着内核被调起来调度下面运行哪一个线程,然后内核调度了线程B,线程B接着也执行了EnterCriticalSection函数的一部分,那么这种情况我觉得很有可能会导致A,B两个线程都通过了EnterCriticalSection函数,获得了临界区中代码的执行权限,这就肯定没有达到临界区互斥的效果。

然后我最近在《现代操作系统》这本书中找到了答案,原来是EnterCriticalSection中直接屏蔽了所有中断来保证自己的执行不被打断,好暴力的操作.....


===============(分割线)===============

jixugengxin,shuzhong说到了一点,直接屏蔽中断并不是一个好的手段,尤其是针对多处理器的情况下,只有一个处理器屏蔽了中断并不能方式别的处理器上运行的线程进入临界区。

更好操作应该是借助于硬件提供的特殊汇编指令,例如TSL指令,该指令访问并且设置个存储器地址上的值(读取后并且设置一个非0值,而且这两个操作不可被打断),并且在这个指令执行期间,其他CPU是不能对该存储器地址进行访问和操作,TSL中的两个操作具有原子性,不能够被打断,在该CPU执行TSL指令的时候会锁住地址总线,防止其他CPU对内存进行访问。

借助这个特性,应该就可以实现比较经典的PV操作了。

例如,利用TSL命令,借助一个标志变量,可以实现多线程多CPU的临界区访问

enter_region:

TSL REGISTER,LOCK   //LOCK在这里就是那个标志变量,使用TSL时读取并且设置了LOCK为非0

CMP REGISTER #0  //判断TSL读出来的LOCK是不是为0,如果不是0说明之前已经有别的CPU或者线程已经在LOCK为0的时候通过了TSL指令并且将LOCK设置为1了,且没有完成临界区中的工作。

JNE enter_region  如果读到的LOCK为非0,说明不能进入临界区,返回到enter_region重新读取这个LOCK

RET  //返回调用者


leave_region:

  MOVE LOCK,#0   //将LOCK设置为0,让其他的线程下次TSL读取到REGISTER中的LOCK为0,让其进入临界区。

  RET

原创粉丝点击