`

C++的原子操作

    博客分类:
  • c++
阅读更多

在多进程(线程)访问资源时,能够确保所有其他的进程(线程)都不在同一时间内访问相同的资源。

  原子操作:UP和SMP的异同

  -----------------------------------------------------------

  原子操作是不可分割的,在执行完毕不会被任何其它任务或事件中断。在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。但是,在对称多处理器(Symmetric Multi-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。我们以decl (递减指令)为例,这是一个典型的"读-改-写"过程,涉及两次内存访问。设想在不同CPU运行的两个进程都在递减某个计数值,可能发生的情况是:

  1. CPU A(CPU A上所运行的进程,以下同)从内存单元把当前计数值(2)装载进它的寄存器中;

  2. CPU B从内存单元把当前计数值(2)装载进它的寄存器中。

  3. CPU A在它的寄存器中将计数值递减为1;

  4. CPU B在它的寄存器中将计数值递减为1;

  5. CPU A把修改后的计数值(1)写回内存单元。

  6. CPU B把修改后的计数值(1)写回内存单元。

  我们看到,内存里的计数值应该是0,然而它却是1。如果该计数值是一个共享资源的引用计数,每个进程都在递减后把该值与0进行比较,从而确定是否需要释放该共享资源。这时,两个进程都去掉了对该共享资源的引用,但没有一个进程能够释放它--两个进程都推断出:计数值是1,共享资源仍然在被使用。

  原子性不可能由软件单独保证--必须需要硬件的支持,因此是和架构相关的。在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。

  Linux内核中的原子操作

  -----------------------------------------------------------

  原子操作大部分使用汇编语言实现,因为c语言并不能实现这样的操作。

  * 在x86的原子操作实现代码中,定义了LOCK宏,这个宏可以放在随后的内联汇编指令之前。如果是SMP,LOCK宏被扩展为lock指令;否则被定义为空 -- 单CPU无需防止其它CPU的干扰,锁内存总线完全是在浪费时间。

  #ifdef CONFIG_SMP

  #define LOCK "lock ; "

  #else

  #define LOCK ""

  #endif

  * typedef struct { volatile int counter; } atomic_t;

  在所有支持的体系结构上原子类型atomic_t都保存一个int值。在x86的某些处理器上,由于工作方式的原因,原子类型能够保证的可用范围只有24位。volatile是一个类型描述符,要求编译器不要对其描述的对象作优化处理,对它的读写都需要从内存中访问。

 

  * #define ATOMIC_INIT(i) { (i) }

  用于在定义原子变量时,初始化为指定的值。如:

  static atomic_t count = ATOMIC_INIT(1);

  * static __inline__ void atomic_add(int i, atomic_t *v)

  ----------------------------------------

  将v指向的原子变量加上i。该函数不关心原子变量的新值,返回void类型。

  在下面的实现中,使用了带有C/C++表达式的内联汇编代码,格式如下(参考《AT&T ASM Syntax》):

  __asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);

  __asm__ __volatile__指示编译器原封不动保留表达式中的汇编指令系列,不要考虑优化处理。涉及的约束还包括:

  1. 等号约束(=):只能用于输出操作表达式约束,说明括号内的左值表达式v->counter是write-only的。

  2. 内存约束(m):表示使用不需要借助寄存器,直接使用内存方式进行输入或输出。

  3. 立即数约束(i):表示输入表达式是一个立即数(整数),不需要借助任何寄存器。

  4. 寄存器约束(r):表示使用一个通用寄存器,由GCC在%eax/%ax/%al、%ebx/%bx/%bl、%ecx/%cx/%cl和%edx/%dx/%dl中选取一个合适的。

  {

  __asm__ __volatile__(

  LOCK "addl %1,%0"

  :"=m" (v->counter)

  :"ir" (i), "m" (v->counter));

  }

  * static __inline__ int atomic_sub_and_test(int i, atomic_t *v)

  ----------------------------------------

  从v 指向的原子变量减去i,并测试是否为0。若为0,返回真,否则返回假。由于x86的subl指令会在结果为0时设置CPU的zero标志位,而且这个标志位是CPU私有的,不会被其它CPU影响。因此,可以执行一次加锁的减操作,再根据CPU的zero标志位来设置本地变量c,并相应返回。

  {

  unsigned char c;

  __asm__ __volatile__(

  LOCK "subl %2,%0; sete %1"

  :"=m" (v->counter), "=qm" (c)

  :"ir" (i), "m" (v->counter) : "memory");

  return c;

  }

  ------------------------------------

  #define atomic_read(v) ((v)->counter)

  读取v指向的原子变量的值。由于该操作本身就是原子的,只需要一次内存访问就能完成,因此定义为一个宏,并用C代码实现。

  #define atomic_set(v,i) (((v)->counter) = (i))

  设置v指向的原子变量的值为i。由于该操作本身就是原子的,只需要一次内存访问就能完成,因此定义为一个宏,并用C代码实现。

  static __inline__ void atomic_sub(int i, atomic_t *v)

  从v指向的原子变量减去i。

  static __inline__ void atomic_inc(atomic_t *v)

  递增v指向的原子变量。

  static __inline__ void atomic_dec(atomic_t *v)

  递减v指向的原子变量。

  static __inline__ int atomic_dec_and_test(atomic_t *v)

  递减v指向的原子变量,并测试是否为0。若为0,返回真,否则返回假。

  static __inline__ int atomic_inc_and_test(atomic_t *v)

  递增v指向的原子变量,并测试是否为0。若为0,返回真,否则返回假。

  static __inline__ int atomic_add_negative(int i, atomic_t *v)

  将v指向的原子变量加上i,并测试结果是否为负。若为负,返回真,否则返回假。这个操作用于实现semaphore。

分享到:
评论

相关推荐

    windows c++ 原子操作例子

    在Windows平台上,C++编程中使用原子操作(Atomic Operations)是为了保证多线程环境下的数据一致性,避免竞态条件和死锁等问题。原子操作是指在多线程环境下,该操作会被完整无中断地执行,不会被其他线程打断。...

    详解C++11原子类型与原子操作

    1.认识原子操作 原子操作就是在多线程程序中“最小的且不可并行化的”操作,意味着多个线程访问同一个资源时,有且仅有一个线程能对资源进行操作。通常情况下原子操作可以通过互斥的访问方式来保证,例如Linux下的...

    C++多线程原子操作

    在C++编程中,多线程环境下的原子操作(Atomic Operations)是确保程序并发执行时数据一致性的重要机制。原子操作是指不可分割的操作,一旦开始执行,就不会被其他线程中断,直到该操作完成。在多线程环境中,不使用...

    C++ 11 开发中的 Atomic 原子操作.rar_C++11、原子_atomic c++_c++ atomic使用_c++

    C++11引入了原子操作(Atomic Operations)作为标准库的一部分,这为多线程编程提供了重要的支持。原子操作在并发环境下确保了数据的完整性,防止了数据竞争和其他并发问题。下面将详细介绍C++11中`std::atomic`的...

    C++ 标准库原子库解析

    这些工具主要涉及原子操作和相关的同步机制,它们为多线程程序提供了一种能够确保内存操作的原子性和线程间一致性的手段。在并发环境下,一个“原子操作”指的是一个不可分割的内存操作序列,这个操作在执行过程中,...

    c++11原子库

    c++11多线程编程之原子库的使用方式,给出了多线程情况下原子数的不可改变性实例

    深入解析C++中的原子操作与原子类型

    C++中的原子操作与原子类型是多线程编程的重要组成部分,它们为处理共享数据提供了高效且安全的方法。原子操作指的是在执行过程中不会被其他线程中断的操作,这样可以保证在多线程环境下对共享数据的安全访问,避免...

    C++中的原子操作:确保并发编程中的线程安全

    本文将详细介绍C++中的原子操作,包括其基本概念、使用场景、API以及如何利用原子操作来避免竞态条件和死锁。 原子操作是C++并发编程中的重要特性,它们为开发者提供了一种高效、灵活且线程安全的方法来处理并发问题...

    多线程程序中的原子操作

    1. **利用编译器或库提供的原子操作支持**:大多数现代编译器和编程语言都提供了原子操作的支持,如C++11标准中的`std::atomic`类型。 2. **手动实现锁机制**:当使用低级语言时,可以手动实现锁机制来保证操作的...

    C++11并发编程关于原子操作atomic的代码示例

    今天小编就为大家分享一篇关于C++11并发编程关于原子操作atomic的代码示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    volatile和原子操作有没有关系,我的实验+别人论文

    探究volatile和原子操作的关系 在多线程编程中,volatile和原子操作都是非常重要的概念。volatile关键字用于告诉编译器不要对变量进行优化,而原子操作则是指不可中断的操作。在本文中,我们将探究volatile和原子...

    c++基础封装(线程、锁、定时器、原子操作等)

    在现代C++中,线程、锁、定时器和原子操作是多线程编程和并发处理的关键概念,它们极大地提升了程序的效率和并行性。下面将详细阐述这些知识点。 一、线程(Thread) 线程是程序执行的最小单元,一个进程可以有多个...

    C++98、C++03、C++11、C++14、C++17、C++20的CHM查询文档

    内容包含:C++11 C++14 C++17 C++20 注释 C++ 编译器支持情况表 独立与宿主实现 C++ 语言 C++ 关键词 ...原子操作库 线程支持库 实验性 C++ 特性 有用的资源 索引 std 符号索引 协程支持 (C++20) C++ 关键词

    Sqlite3 C++ 简单单例数据库操作类封装

    为了保证线程安全,单例类的实例化通常会在第一次调用`getInstance()`时进行,使用互斥锁或原子操作来确保多线程环境下的正确性。此外,还需要考虑在程序退出时关闭数据库连接,防止资源泄露。 总结来说,"Sqlite3 ...

    c++20标准_c++20标准_

    9. **原子浮点数操作(Atomic Floating-Point Operations)**:`std::atomic`增加了对浮点数的支持,使得在并发环境中安全地处理浮点数成为可能。 10. **改进的字面量操作符(Improved Literal Operators)**:C++...

    C++操作Access数据库(ADO)VS2010 MFC

    - 使用`BeginTrans`, `CommitTrans` 和 `RollbackTrans`进行事务管理,确保数据操作的原子性和一致性。 5. **关闭数据库连接**: - 记得在完成所有操作后关闭数据库连接,以释放资源。 ```cpp db.Close(); ``` ...

    C++ 原子类型

    文章目录atomic构造赋值访问特化操作atomic_flag构造操作内存序 原子对象可以保证:从不同的线程访问其包含的数据不会造成数据竞争。此外,它还能够同步不同线程对内存的访问。 atomic 构造 default (1) atomic()...

    C++日志操作

    此外,多线程环境下的日志操作需要考虑线程安全,可能通过互斥锁或者原子操作来防止数据竞争。 总结来说,"C++日志操作"项目提供了一个实用的日志工具,它不仅支持多种开发环境,还具有日志文件大小控制的智能管理...

Global site tag (gtag.js) - Google Analytics