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