zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    使<div>做的层不随滚动条的移动而移动
    datagrid 实现 表头水平可以移动 垂直固定
    csapp 、sicp 、深入理解计算机系统、 计算机程序的构造和解释
    window.open使用
    C#进程管理
    asx根据时间点播放
    Ext GrdPanel多种取值方式
    System.ComponentModel.Win32Exception: 拒绝访问
    播放器Object使用
    M3U文件格式
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/12989849.html
Copyright © 2011-2022 走看看