C/C++ 基本类型是原子的吗? [英] Are C/C++ fundamental types atomic?

查看:33
本文介绍了C/C++ 基本类型是原子的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是 C/C++ 基本类型,如 intdouble 等,是原子的,例如线程安全?

他们是否没有数据竞争?也就是说,如果一个线程写入这种类型的对象而另一个线程从中读取,那么行为是否定义良好?

如果不是,是取决于编译器还是其他什么?

解决方案

不,基本数据类型(例如,intdouble)不是原子的,参见 std::atomic.

相反,您可以使用 std::atomicstd::atomic.

注意: std::atomic 是在 C++11 中引入的,我的理解是在 C++11 之前,C++ 标准不识别多线程的存在.

<小时>

正如@Josh 所指出的,std::atomic_flag 是一个原子布尔类型.与 std::atomic 特化不同,它保证无锁.

<小时>

引用的文档来自:http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf.我很确定该标准不是免费的,因此这不是最终/正式版本.

1.10 多线程执行和数据竞争

<块引用>

  1. 如果其中一个修改内存位置 (1.7) 而另一个读取或修改相同的内存位置,则两个表达式计算会发生冲突.
  2. 该库定义了许多原子操作(第 29 条)和互斥体上的操作(第 30 条),它们被专门标识为同步操作.这些操作在使一个线程中的分配对另一个线程可见方面发挥着特殊作用.对一个或多个内存位置的同步操作是消耗操作、获取操作、释放操作,或获取和释放操作.没有关联内存位置的同步操作是一个栅栏,可以是获取栅栏、释放栅栏或同时是获取栅栏和释放栅栏.此外,还有非同步操作的宽松原子操作和具有特殊特性的原子读-修改-写操作.


<块引用>

  1. 两个动作可能同时发生,如果
    (23.1) — 它们由不同的线程执行,或
    (23.2) — 它们是未排序的,并且至少有一个由信号处理程序执行.
    如果一个程序包含两个潜在的并发冲突操作,则该程序的执行包含数据竞争,其中至少一个不是原子的,并且都不在另一个之前发生,除了下面描述的信号处理程序的特殊情况.任何此类数据竞争都会导致未定义的行为.

29.5 原子类型

<块引用>

  1. 对于整数类型``char,signed charunsigned charshortunsigned shortintunsigned intlongunsigned longlong longunsigned long longchar16_t、char32_twchar_t 和任何其他类型标题 中的 typedef 需要.对于每个整型积分,特化 atomic 提供了适用于整型的附加原子操作.应该有一个专门化的atomic,它提供了 29.6.1..
  2. 中规定的一般原子操作


<块引用>

  1. 应该有原子类模板的指针部分特化.这些专业化应具有标准布局、平凡的默认构造函数和平凡的析构函数.它们都应支持聚合初始化语法.

29.7 标志类型和操作

<块引用>

  1. 对 atomic_flag 类型的对象的操作应该是无锁的.[注意:因此操作也应该是无地址的.没有其他类型需要无锁操作,因此 atomic_flag 类型是符合此国际标准所需的最低硬件实现类型.其余类型可以使用 atomic_flag 进行模拟,尽管属性不太理想.— 尾注 ]

Are C/C++ fundamental types, like int, double, etc., atomic, e.g. threadsafe?

Are they free from data races; that is, if one thread writes to an object of such a type while another thread reads from it, is the behavior well-defined?

If not, does it depend on the compiler or something else?

解决方案

No, fundamental data types (e.g., int, double) are not atomic, see std::atomic.

Instead you can use std::atomic<int> or std::atomic<double>.

Note: std::atomic was introduced with C++11 and my understanding is that prior to C++11, the C++ standard didn't recognize the existence of multithreading at all.


As pointed out by @Josh, std::atomic_flag is an atomic boolean type. It is guaranteed to be lock-free, unlike the std::atomic specializations.


The quoted documentation is from: http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf. I'm pretty sure the standard is not free and therefore this isn't the final/official version.

1.10 Multi-threaded executions and data races

  1. Two expression evaluations conflict if one of them modifies a memory location (1.7) and the other one reads or modifies the same memory location.
  2. The library defines a number of atomic operations (Clause 29) and operations on mutexes (Clause 30) that are specially identified as synchronization operations. These operations play a special role in making assignments in one thread visible to another. A synchronization operation on one or more memory locations is either a consume operation, an acquire operation, a release operation, or both an acquire and release operation. A synchronization operation without an associated memory location is a fence and can be either an acquire fence, a release fence, or both an acquire and release fence. In addition, there are relaxed atomic operations, which are not synchronization operations, and atomic read-modify-write operations, which have special characteristics.


  1. Two actions are potentially concurrent if
    (23.1) — they are performed by different threads, or
    (23.2) — they are unsequenced, and at least one is performed by a signal handler.
    The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, at least one of which is not atomic, and neither happens before the other, except for the special case for signal handlers described below. Any such data race results in undefined behavior.

29.5 Atomic types

  1. There shall be explicit specializations of the atomic template for the integral types ``char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, char16_t, char32_t, wchar_t, and any other types needed by the typedefs in the header <cstdint>. For each integral type integral, the specialization atomic<integral> provides additional atomic operations appropriate to integral types. There shall be a specialization atomic<bool> which provides the general atomic operations as specified in 29.6.1..


  1. There shall be pointer partial specializations of the atomic class template. These specializations shall have standard layout, trivial default constructors, and trivial destructors. They shall each support aggregate initialization syntax.

29.7 Flag type and operations

  1. Operations on an object of type atomic_flag shall be lock-free. [ Note: Hence the operations should also be address-free. No other type requires lock-free operations, so the atomic_flag type is the minimum hardware-implemented type needed to conform to this International standard. The remaining types can be emulated with atomic_flag, though with less than ideal properties. — end note ]

这篇关于C/C++ 基本类型是原子的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆