C#中的原子操作
-
原子操作的介绍
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何的线程切换,它不一定是一条指令,可以是多条指令。 -
原子操作的原理
- 一般情况下,当我们对一个整型变量进行加一操作的时候,会有三个操作:
(1)从内存中将该变量加载带CPU寄存器中
(2)CPU对该变量进行加一操作
(3)将该变量从CPU寄存器返回内存中
1).在单核CPU中,由于线程的抢占机制,高优先级的线程可能会抢占低优先级的线程,如果低优先级的线程在对一个变量进行加一操作的时候,运行了前一个或者两个步骤,接下来就被另一个线程抢占,并且也对该变量进行加一操作,那么在这个高优先级线程运行完成再继续运行低优先级的第二或者第三个步骤,其变量仍然实在原来的基础上加一的,所以在两个线程运行完成时,该变量只加了一次,只要能够保证指令的顺序不被打乱,那么便能保证该操作的原子性。
2).但是,在多核的CPU中,保证CPU的指令执行顺序依然是不够的,在多核CPU中,可以存在多个线程同时运行,如果恰好有两个或者多个线程正在对该变量进行加一操作,当这些线程都将变量从内存加载到寄存器中时,那么他们的值依然不是最新的,这依然会导致最终只执行了一次加一操作。
- 原子操作的实现方法
现在一般的CPU可以使用总线锁和缓存锁来实现:
(1).CPU在硬件上可以通过拉低引线来实现总线锁,当需要进行一个原子操作时,CPU就可以拉低引线,将总线锁住,实现其他CPU与内存之间的通讯隔离,这样,其他的CPU就不能够从内存中读取数据了。
(2).由于总线锁会中断其他CPU与内存之间的通讯,导致在这段时间内其他CPU访问不到内存,效率降低,因此总线锁的开销是很大的,于是又出现了一种新的方式,缓存锁。
缓存锁不会阻断CPU与内存之间的通讯,内存中的一个变量可以被多个核心访问,其缓存行有被修改的、独享的、共享的、无效的这四种状态,简单的来说,在某个CPU修改变量时,会将其他CPU中的缓存置为无效的,从而保证在修改时,每个CPU核心中的值都是最新的。