用汇编实现原子操作

原创 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__


x86平台原子操作API的实现原理

x86平台原子操作API的实现原理
  • infinite_sh
  • infinite_sh
  • 2015-03-13 09:30:21
  • 726

linux内核原子操作的实现

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

操作系统概念-内核同步-原子操作

在同一个操作系统中,不同的进程经常需要相互协同工作,协同的方法一般有两种,一是直接共享逻辑地址空间,二是通过文件或消息共享数据。如果共享逻辑地址空间,则在进程执行的时候有可能会发生多个进程同时访问同一...
  • u010281174
  • u010281174
  • 2016-12-28 21:09:02
  • 1684

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

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

用汇编实现原子操作

原子操作(1) - 用汇编实现原子操作 “最轻量级的锁”,通常也叫”原子操作”,之所以加引号是因为他们在汇编级别并不是原子操作,是用多条指令完成的,这些操作大多都是利用CPU支持的汇编指令.在某些构...
  • zacklin
  • zacklin
  • 2012-04-10 14:46:02
  • 1576

原子操作

weGNU C中x++是原子操作吗? 答案:不是。x++由3条指令完成。x++在单CPU下不是原子操作。 对应3条汇编指令 movl x, %eax addl $1, %eax movl %...
  • chenwenxin
  • chenwenxin
  • 2014-11-23 23:18:45
  • 555

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

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

C++原子操作实现互斥

所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线...
  • Angus_Sun
  • Angus_Sun
  • 2016-10-04 17:23:00
  • 786

C++11(boost)中的原子操作(atomic operation)

本文转自:http://blog.csdn.net/yockie/article/details/8838686 所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在...
  • Sunshine_in_Moon
  • Sunshine_in_Moon
  • 2016-04-09 16:12:52
  • 1441

聊聊原子操作那些事

原子操作,线程间交互数据最细粒度的同步操作,它可以保证线程间读写某个数值的原子性。由于不需要加重量级的互斥锁进行同步,因此非常轻量,而且也不需要在内核间来回切换调度,效率是非常高的。。那如何使用原子操...
  • waruqi
  • waruqi
  • 2016-11-17 16:07:14
  • 1142
收藏助手
不良信息举报
您举报文章:用汇编实现原子操作
举报原因:
原因补充:

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