用汇编实现原子操作

原创 2012年04月10日 14:46:02

原子操作(1) - 用汇编实现原子操作

最轻量级的锁”,通常也叫原子操作”,之所以加引号是因为他们在汇编级别并不是原子操作,是用多条指令完成的,这些操作大多都是利用CPU支持的汇编指令.在某些构架过时的CPU体系结构上,它们应该是用比较重量级的线程内锁实现的吧(我的猜测).

最常见的原子操作有Compare and Exchange,Self Increase/Decrease等等

80486 CPU相关指令:

LOCK:这是一个指令前缀,在所对应的指令操作期间使此指令的目标操作数指定的存储区域锁定,以得到保护。

XADD:先交换两个操作数的值,再进行算术加法操作。多处理器安全,在80486及以上CPU中支持。

CMPXCHG:比较交换指令,第一操作数先和AL/AX/EAX比较,如果相等ZF1,第二操作数赋给第一操作数,否则ZF0,第一操作数赋给AL/AX/EAX。多处理器安全,在80486及以上CPU中支持。

XCHG:交换两个操作数,其中至少有一个是寄存器寻址.其他寄存器和标志位不受影响.

80486以上都支持这四个操作,因此当今几乎100%CPU都支持这两个指令,也能由此用标准CC++写出一系列几乎可以跨平台的原子操作函数和Lock-Free数据结构和算法.

64位平台也有一系列的相关指令,当然他们也有以上提到的指令,其下的64位原子操作函数应该和32位的分开(要问为什么?我现在告诉你恐怕你印象不深,接着看这一系列吧),而道理完全一样.因此,不存在跨CPU体系结构的问题)

原子操作函数:

由以上提供的几个汇编指令,我们可以做出以下实现,这些都是最常用的原语.

比较后交换

long __stdcall CompareExchange(long volatile*Destination,long Exchange,long Comperand)

{

   __asm

   {

      mov     ecx, Destination;

      mov     edx, Exchange;

      mov     eax, Comperand;

      lock cmpxchg [ecx], edx;

   }

}

交换

long __stdcall Exchange(long volatile* Target,long Value)

{

   __asm

   {

      mov      ecx, Target;

      mov      edx, Value;

label:

      lock cmpxchg [ecx], edx;//

      jnz      short label;

   }

}

自减

long __stdcall Decrement(long volatile* Addend)

{

   __asm

   {

      mov     ecx, Addend;

      mov     eax, 0FFFFFFFFh;//-1

      lock xadd [ecx], eax; //-1

      dec     eax;

   }

}

自增

long __stdcall Increment(long volatile* Addend)

{

   __asm

   {

      mov      ecx, Addend;

      mov      eax, 1;

      lock xadd [ecx], eax; //

      inc      eax;

   }

}

相加后交换

long __stdcall ExchangeAdd(long volatile* Addend,long Value)

{

   __asm

   {

      mov      ecx, Addend;

      mov      eax, Value;

      lock xadd [ecx], eax;

   }

}

 

 

原子操作(2) - 泛型后的原子操作

32位的数据类型有4,但是上面的只支持long,怎么办?手工hack?太土了,当然是C++的大规模杀伤性武器template.

同时把几个不跨平台的地方抽出来用macro表示.

目前模板还没有得到concept的支持,所以只能用boost.type_traits低级的手动判断,要求只有32位的整数类型才能实例化这些函数.

 

 

 

#include

#include

 

#define CALL_METHOD __stdcall

#define VOLATILE volatile

 

template<typename T>

T CALL_METHOD compare_exchange32(T VOLATILE*Destination,T exchange32,T Comperand)

{

   BOOST_STATIC_ASSERT(sizeof(T) == 4 && boost::is_integral<T>::value);

   __asm

   {

      mov     ecx, Destination;

      mov     edx, exchange32;

      mov     eax, Comperand;

      lock cmpxchg [ecx], edx;

   }

}

 

 

 

 

template<typename T>

T CALL_METHOD exchange32(T VOLATILE* Target,T Value)

{

   BOOST_STATIC_ASSERT(sizeof(T) == 4 && boost::is_integral<T>::value);

   __asm

   {

      //     mov    ecx, Target;

      //     mov    edx, Value;      

      //label:

      //     lock   cmpxchg [ecx], edx;//

      //     jnz    short label;

      mov      ecx, Target;

      mov      eax, Value;

      xchg [ecx],eax;

   }

}

 

 

 

template<typename T>

T CALL_METHOD decrement32(T VOLATILE* Addend)

{

   BOOST_STATIC_ASSERT(sizeof(T) == 4 && boost::is_integral<T>::value);

   __asm

   {

      mov     ecx, Addend;

      mov    eax, 0FFFFFFFFh;//-1

      lock xadd [ecx], eax; //-1

      dec     eax;

   }

}

 

 

 

 

template<typename T>

T CALL_METHOD increment32(T VOLATILE* Addend)

{

   BOOST_STATIC_ASSERT(sizeof(T) == 4 && boost::is_integral<T>::value);

   __asm

   {

      mov      ecx, Addend;

      mov      eax, 1;

      lock xadd [ecx], eax; //

      inc      eax;

   }

}

 

 

template<typename T>

T CALL_METHOD exchange_add32(T VOLATILE* Addend,T Value)

{

   BOOST_STATIC_ASSERT(sizeof(T) == 4 && boost::is_integral<T>::value);

   __asm

   {

      mov      ecx, Addend;

      mov      eax, Value;

      lock xadd [ecx], eax;

   }

}

 

原子操作(3) - 原子数类

根据上面的5个函数就能做出一个原子操作的整数数字类,这将是下一节中,我的最轻量级锁的基础和原型,他不依赖于操作系统,当然,所以你也可以不叫他是锁,只是一种类似锁的机制.

一切细节看源码中穿插的注释.

#ifndef __ATOM_VALUE_H__

#define __ATOM_VALUE_H__

 

#include "atom.hpp"

#include <boost/static_assert.hpp>

#include <boost/type_traits.hpp>

 

template<typename T>

class atomic_value32

{

   //,boost.type_traits来保证是位的整数类型

   BOOST_STATIC_ASSERT(sizeof(T) == 4 && boost::is_integral<T>::value);

 

private:

   volatile T value_;

 

public:

   atomic_value32(T v = 0)

      :value_(v){}

 

   atomic_value32(atomic_value32& v){//??? 这里留给大家,我不给出源码了

   }

 

   //需要这么一个转型符号,因为大部分时候我们将atomic_value32<T>当作一个T使用

   operator T(){return exchange_add32(&value_,0);}

 

   //赋值

   atomic_value32& operator=(T v){exchange32(&value_, v);return *this;}

   atomic_value32& operator=(atomic_value32& v){exchange32(&value_, v);return *this;}

 

   //比较并交换,好像没有什么operator与之对应,就直接拿出来了

   T compare_exchange(T to_exchange, T to_compare)

   {return compare_exchange32<T>(&value_, to_exchange, to_compare);}

 

   //只提供前置,后置似乎没什么必要,我也懒得去实现了:)

   T operator++(){return increment32(&value_);}

   T operator--(){return decrement32(&value_);}

 

   //千万不能返回引用,因为线程安全考虑,

   T operator+=(T add){return exchange_add32(&value_,add);}

   T operator+=(atomic_value32& add){return exchange_add32(&value_,add);}

   T operator-=(T add){return exchange_add32(&value_,-add);}

   T operator-=(atomic_value32& add){return exchange_add32(&value_,-add);}

 

   //6个比较符号

   bool operator==(T rhs){return operator T()==rhs;}

   bool operator==(atomic_value32& rhs){return operator T()==rhs.operator T();}

   bool operator<(T rhs){return operator T()<rhs;}

   bool operator<(atomic_value32& rhs){return operator T()<rhs.operator T();}

   bool operator!=(T rhs){return !this->operator ==(rhs);}

   bool operator!=(atomic_value32& rhs){return !this->operator ==(rhs);}

   bool operator>=(T rhs){return !this->operator <(rhs);}

   bool operator>=(atomic_value32& rhs){return !this->operator <(rhs);}

   bool operator>(T rhs){return ((*this)!=(rhs)) && !((*this)<(rhs));}

   bool operator>(atomic_value32& rhs){return ((*this)!=(rhs)) && !((*this)<(rhs));}

   bool operator<=(T rhs){return !((*this)>(rhs));}

   bool operator<=(atomic_value32& rhs){return !((*this)>(rhs));}

};

 

 

 

#endif//__ATOM_VALUE_H__


linux内核原子操作的实现

所谓原子操作,就是“不可中断的一个或一系列操作”。硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。在多处理...
  • vividonly
  • vividonly
  • 2011年07月12日 12:53
  • 14095

关于atomic_t 原子变量的操作

yuan 所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念。   原子...
  • zhaoxiaoqiang10
  • zhaoxiaoqiang10
  • 2014年09月23日 18:01
  • 2464

原子变量自增的实现

原子变量自增大致有两种方式;一种是基于CPU硬件支持,而另一种为软件层面自旋实现;两者各有各的优势;理论上说软件 层面的现实是最通用的,不过它也带来了一些棘手的问题比如每个线程都在高频率的执行原子自...
  • liulilittle
  • liulilittle
  • 2018年01月06日 20:28
  • 39

【转】用汇编实现原子操作

 原子操作是不可分割的,在执行完毕不会被任何其它任务或事件中断。在单处理器系统(UniProcessor)中, 能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。这也是...
  • code09
  • code09
  • 2011年07月01日 13:19
  • 3189

cpu cmpxchg 指令理解 (CAS)

cmpxchg是汇编指令 作用:比较并交换操作数. 如:CMPXCHG r/m,r 将累加器AL/AX/EAX/RAX中的值与首操作数(目的操作数)比较,如果相等,第2操作数(源操作数)的值装载到首操...
  • xiuye2015
  • xiuye2015
  • 2016年11月30日 12:46
  • 2939

关于int全区变量读写的原子性

关于int全区变量读写的原子性     关于int变量的读写是否原子性网上有很多讨论,貌似不同平台不同,这里自己做实现在arm9平台测试。这里要注意原子性并非指一条汇编才原子,实际上即使一次...
  • huanghui167
  • huanghui167
  • 2014年11月21日 11:24
  • 3534

原子操作 atomic_t

1. atomic_t 定义及其原因: 内核定义了atomic_t 数据类型,作为对整数计数器的原子操作的基础。 [cpp] view plaincopy typedef...
  • JK198310
  • JK198310
  • 2014年05月09日 17:25
  • 1261

原子操作(1) - 用汇编实现原子操作

“最轻量级的锁”,通常也叫”原子操作”,之所以加引号是因为他们在汇编级别并不是原子操作,是用多条指令完成的,这些操作大多都是利用CPU支持的汇编指令.在某些构架过时的CPU体系结构上,它们应该是用比较...
  • Mirage520
  • Mirage520
  • 2015年03月05日 16:56
  • 504

汇编原子操作实现(转载)

内容均是转载自 http://www.cppblog.com/woaidongmao/archive/2009/10/19/98965.html 原子操作(1) - 用汇编实现原子操作 ...
  • dfasri
  • dfasri
  • 2011年09月21日 15:50
  • 598

Linux驱动之原子变量

使用原子变量可以避免竞争问题。其实,很多的同步技术都使用了原子变量,例如自旋锁。 它的名称是 atomic_t, 实际上是一个int类型。不过由于某些处理器上这种数据类型的工作方式有些限制,因此不能...
  • king523103
  • king523103
  • 2015年02月12日 17:31
  • 566
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用汇编实现原子操作
举报原因:
原因补充:

(最多只允许输入30个字)