锁:CAS

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/y3over/article/details/88422118

操作系统实现锁的方式:
          1.对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位。
          2.多处理器,利用test_and_set,Compare_and_swap指令实现进程互斥.

                   因此,CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。所以,当多个线程执行CAS操作并且CAS的步骤很多,有没有可能在判断V和E相同后,正要赋值时,切换了线程,更改了值。造成了数据不一致的情况是不存在的。


#define LOCKED 1
int TestAndSet(int* lockPtr) {//传入一地址
     int oldValue;//声明一变量 
     oldValue = *lockPtr;//把变量设置为 lockPtr地址所指往的值
    *lockPtr = LOCKED;//把原变量设为1
     return oldValue;//返回旧值
}


volatile int lock = 0;

void Critical() {
     while (TestAndSet(&lock) == 1);
     //to do 我们要写的业务代码
     lock = 0 //解放我们的锁 
}


现在线程1,2调用Critical,因为test_and_set 是指令实现为原子性。
假设如果 线程1先进入,  lock=1并反回 0; 然后执行业务代码,然后线程2进入,lock=1,返回1,继续自旋。直到1将锁释放。
Compare_and_swap 则是对test_and_set升级。因为 test_and_set 的 LOCKED 已经定死了。
int compare_and_swap(int* reg, int oldval, int newval)

意思是 oldval和你期望值是否相等,如果相等则设值为newval,并返回老值。 

 

CAS的缺点:

CAS虽然很高效的解决了原子操作问题,但是CAS仍然存在三大问题。

    1.循环时间长开销很大。

          如果CAS长时间一直不成功,可能会给CPU带来很大的开销。

         (可以试2次CAS,然后挂起线程解决)

    2.只能保证一个共享变量的原子操作。

         当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。

        (可以,用一个CAS来获取共享变量的操作权限,从而达到控制多个变量的效果)

     3.ABA问题。

            如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说它的值没有被其他线程改变过了吗?如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。

扫描二维码关注公众号,回复: 5652991 查看本文章

        (Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。)
 

猜你喜欢

转载自blog.csdn.net/y3over/article/details/88422118