CAS 原理 应用

Posted zytcomeon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CAS 原理 应用相关的知识,希望对你有一定的参考价值。

  • 原子CAS操作

原子操作指令里,有原子加,原子减,cas到底是什么呢?

首先看一段代码,

bool compare_and_swap(int *accum, int *dest, int newval)
{
  if (*accum == *dest) {
      *dest = newval;
      return true;
  } else {
      *accum = *dest;
      return false;
  }
}

cas即是Compare-and-swap,先比较再互换,即修改,意思就是,当reg等oldvalue的时候,将reg设置为newval,这段代码在非原子情况下(多线程)是没用的.

CAS操作,到底有什么威力?

    如果要修改一个变量,在多线程下,应该要加锁,代码是这样的

int num = 0;
void add()
{
    lock();
    num = num + 123;
    unlock();
}

但是如果不要锁,cas来操作??

int num = 0;
void add()
{
    int temp;
    do
    {
        temp = num;
    }
    while (cas(num, temp, temp+123)==true)
}

 

先让temp目的值=num实际值,如何这个过程中num的值没有改变(temp==num值)则,将新值temp=123 复制给num,跳出循环;

如何第一次发生了变化,那么在读read一次num的值给temp,再次cas比较

  • 2=.研究 cmpxchg指令

cmpxchg是汇编指令
作用:比较并交换操作数.
如:CMPXCHG r/m,  r

      ==>   cmpxchg  (目的操作数, 源操作数,RAX寄存器)

 

将累加器AL/AX/EAX/RAX中的值与首操作数(目的操作数)比较,如果相等,第2操作数(源操作数)的值装载到首操作数,zf置1。

如果不等, 首操作数的值装载到AL/AX/EAX/RAX并将zf清0

#include<iostream>
using namespace std;
int main(){
    int a=0,b=0,c=0;
 
    __asm{
        mov eax,100;
        mov a,eax
    }
    cout << "a := " << a << endl;
    b = 99;
    c = 11;
    __asm{
        mov ebx,b
        cmpxchg c,ebx //将累加器EAX中的值与首操作数(目的操作数)c=11比较 eax=100 != c=11,即不相等,eax=c;
        mov a,eax    
    }
    cout << "b := " << b << endl;
    cout << "c := " << c << endl;
    cout << "a := " << a << endl;
    return 0;
}

输出:(如果不等, "首操作数"(c)的值装载到AL/AX/EAX/RAX并将zf清0)

a := 100
b := 99
c := 11
a := 11

 

#include<iostream>
using namespace std;
int main(){
    int a=0,b=0,c=0;
 
    __asm{
        mov eax,100;
        mov a,eax
    }
    cout << "a := " << a << endl;
    b = 99;
    c = 99;
    __asm{
        mov eax,99
        mov ebx,777
        cmpxchg c,ebx //将累加器EAX=99中的值与首操作数(目的操作数)c=99比较,相等,第2操作数(源操作数)ebx的值装载到首操作数c(c=ebx=777),zf置1。
        mov a,eax
    }
    cout << "b := " << b << endl;
    cout << "c := " << c << endl;
    cout << "a := " << a << endl;
    return 0;
}

输出:(如果相等,第2操作数(源操作数)的值装载到首操作数,zf置1)

a := 100
b := 99
c := 777
a := 99

3=.多线程编程中如何解决数据安全的问题?

package com.tedu;

import java.util.concurrent.atomic.AtomicInteger;

public class MoneyRunnable implements Runnable {
    private AtomicInteger sumMoney= new AtomicInteger(100);

    @Override
    public void run() {

    while (true){

        Data.lock.lock();
        if(sumMoney.get()>0){
            System.out.println(Thread.currentThread().getName() + "获得一元钱");
            if (Thread.currentThread().getName().equals("张三")) {
                Data.zsMoney++;
            } else if (Thread.currentThread().getName().equals("李四")) {
                Data.lsMoney++;
            } else {
                Data.wwMoney++;
            }
            sumMoney.decrementAndGet();
            System.out.println(sumMoney.get());

        }else {
            System.out.println("钱抢完了");
            System.out.println("张三获得了:" + Data.zsMoney);
            System.out.println("李四获得了:" + Data.lsMoney);
            System.out.println("王五获得了:" + Data.wwMoney);
            System.out.println("他们一共获得了:"+(Data.zsMoney+Data.wwMoney+Data.lsMoney));
            break;
        }
        try {
            Thread.sleep(400);
        }catch (Exception e){e.printStackTrace();}

        Data.lock.unlock();
    }

    }
}
package com.tedu;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Data {
    public static int zsMoney=0; //张三zs
    public static int lsMoney=0;//李四
    public static int wwMoney=0;//王五

    public static int zsMoneyHitNum=0;
    public static int  lsHitNum=0;
    public static int  wwHitNum=0;

    public static Object lockObject1= new Data();
    public static Object lockObject2=new Data();
    public static Lock lock = new ReentrantLock();
}
package com.tedu;

public class MainApp {
    public static void main(String[] args) {
        MoneyRunnable my1 = new MoneyRunnable();
        Thread t1 = new Thread(my1);
        Thread t2= new Thread(my1);
        Thread t3 = new Thread(my1);
        t1.setName("张三");
        t2.setName("李四");
        t3.setName("王五");
        t1.start();
        t2.start();
        t3.start();

    }
}

 这个用sychronized的,和lock的用法一样

while (true) { 
/**
* 同步代码块实现数据安全:
* 
* 这里面的this就是一把锁,使用这个类创建的线程使用同一把锁
* 
*/
synchronized (this) {
if (sumMoney > 0) {
 
/**
* sumMoney = sumMoney - 1; 放在前面就不会有问题
*/
// sumMoney = sumMoney - 1;
System.out.println(Thread.currentThread().getName() + "获得一元钱");
if (Thread.currentThread().getName().equals("张三")) {
Data.zsMoney++;
} else if (Thread.currentThread().getName().equals("李四")) {
Data.lsMoney++;
} else {
Data.wwMoney++;
}
 
/**
* sumMoney = sumMoney - 1; 放在后面就会出现数据安全问题(线程安全问题)
*/
sumMoney = sumMoney - 1;
} else {
System.out.println("钱分完了:");
System.out.println("张三获得了:" + Data.zsMoney);
System.out.println("李四获得了:" + Data.lsMoney);
System.out.println("王五获得了:" + Data.wwMoney);
System.out.println("他们一共获得了:" + (Data.zsMoney + Data.wwMoney + Data.lsMoney));
try {
// 防止数据刷的过快,休眠一段时间
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
 
}
}

 

atzhang

以上是关于CAS 原理 应用的主要内容,如果未能解决你的问题,请参考以下文章

CAS 原理 应用

Java -- 每日一问:AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

[多线程进阶]CAS与Synchronized基本原理

非阻塞式的原子性操作-CAS应用及原理

Java CAS原理

JAVA CAS原理深度分析(*)