前面三篇文章《
C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)
》、《
C++11 并发指南六( <atomic> 类型详解二 std::atomic )
》、《
C++11 并发指南六(atomic 类型详解三 std::atomic (续))
》都是采用 C++ 的方式介绍原子对象,本节我会给大家介绍 C++11 原子操作中 C 风格的 API。
总地来说,C++11 标准中规定了两大类原子对象,std::atomic_flag 和 std::atomic,前者 std::atomic_flag 一种最简单的原子布尔类型,只支持两种操作,test-and-set 和 clear。而 std::atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值,并且C++11 标准中除了定义基本 std::atomic 模板类型外,还提供了针对整形(integral)和指针类型的特化实现,提供了大量的 API,极大地方便了开发者使用。下面我分别介绍基于 std::atomic_flag 和 std::atomic 的 C 风格 API。
基于 std::atomic_flag 类型的 C 风格 API
atomic_flag_test_and_set
bool atomic_flag_test_and_set (volatile atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set (atomic_flag* obj) noexcept;
检测并设置 std::atomic_flag 的值,并返回 std::atomic_flag 的旧值,和 std::atomic::test_and_set() 成员函数的功能相同,整个过程也是原子的,默认的内存序为memory_order_seq_cst。
atomic_flag_test_and_set_explicit
bool atomic_flag_test_and_set (volatile atomic_flag* obj, memory_order sync) noexcept;
bool atomic_flag_test_and_set (atomic_flag* obj, memory_order sync) noexcept;
检测并设置 std::atomic_flag 的值,并返回 std::atomic_flag 的旧值,和 std::atomic::test_and_set() 成员函数的功能相同,整个过程也是原子的。sync 参数指定了内存序(Memory Order),可能的取值如下:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_flag_clear
void atomic_flag_clear (volatile atomic_flag* obj) noexcept;
void atomic_flag_clear (atomic_flag* obj) noexcept;
清除 std::atomic_flag 对象,并设置它的值为 false,和 std::atomic::clear() 成员函数的功能相同,整个过程也是原子的,默认的内存序为memory_order_seq_cst。
atomic_flag_clear_explicit
void atomic_flag_clear (volatile atomic_flag* obj, memory_order sync) noexcept;
void atomic_flag_clear (atomic_flag* obj, memory_order sync) noexcept;
清除 std::atomic_flag 对象,并设置它的值为 false,和 std::atomic::clear() 成员函数的功能相同,整个过程也是原子的,sync 参数指定了内存序(Memory Order),可能的取值如下:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
基于 std::atomic 模板类型的 C 风格 API
atomic_is_lock_free
template (1) |
|
---|---|
overloads (2) |
|
判断该 std::atomic 对象是否具备 lock-free 的特性。如果某个对象满足
lock-free
特性,在多个线程访问该对象时不会导致线程阻塞。(可能使用某种事务内存
transactional memory
方法实现 lock-free 的特性)。
atomic_init
template (1) |
|
---|---|
overloads (2) |
|
初始化原子对象。val 指定原子对象的初始值。如果对一个已初始化的原子对象再次调用 atomic_init(),则会导致未定义行为(
undefined behavior
),如果你想修改原子对象的值,应该使用 std::atomic_store();
atomic_store
template (1) |
|
---|---|
overloads (2) |
|
修改原子对象的值,默认的内存序为memory_order_seq_cst。该函数相当于 std::atomic 对象的 store 或者operator=() 成员函数,如果你需要显式指定内存序,应该使用atomic_store_explicit。
atomic_store_explicit
修改原子对象的值。该函数相当于 std::atomic 对象的 store 或者operator=() 成员函数,sync 指定了内存序,可取的参数为:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_release | Release |
memory_order_seq_cst | Sequentially consistent |
atomic_load
template (1) |
|
---|---|
overloads (2) |
|
读取被封装的值,默认的内存序为memory_order_seq_cst。该函数与 std::atomic 对象的atomic::load()和atomic::operator T() 成员函数等价。
atomic_load_explicit
template (1) |
|
---|---|
overloads (2) |
|
读取被封装的值,参数 sync 设置内存序(Memory Order),可能的取值如下:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_seq_cst | Sequentially consistent |
该函数与 std::atomic 对象的atomic::load() 成员函数等价。
atomic_exchange
template (1) |
|
---|---|
overloads (2) |
|
读取并修改被封装的值,exchange 会将 val 指定的值替换掉之前该原子对象封装的值,并返回之前该原子对象封装的值,整个过程是原子的(因此exchange 操作也称为
read-modify-write
操作)。该函数与 std::atomic 对象的atomic::exchange() 成员函数等价。
atomic_exchange_explicit
template (1) |
|
---|---|
overloads (2) |
|
读取并修改被封装的值,exchange 会将 val 指定的值替换掉之前该原子对象封装的值,并返回之前该原子对象封装的值,整个过程是原子的(因此exchange 操作也称为
read-modify-write
操作)。sync参数指定内存序(Memory Order),可能的取值如下:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_compare_exchange_weak
template (1) |
|
---|---|
overloads (2) |
|
比较并交换被封装的值(weak)与参数 expected 所指定的值是否相等,如果:
- 相等,则用 val 替换原子对象的旧值。
-
不相等,则用原子对象的旧值替换
expected
,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,
expected
中的内容就是原子对象的旧值。
该函数通常会读取原子对象封装的值,如果比较为 true(即原子对象的值等于
expected
),则替换原子对象的旧值,但整个操作是原子的,在某个线程读取和修改该原子对象时,另外的线程不能对读取和修改该原子对象。
注意,该函数直接比较原子对象所封装的值与参数
expected
的物理内容,所以某些情况下,对象的比较操作在使用 operator==() 判断时相等,但 atomic_compare_exchange_weak 判断时却可能失败,因为对象底层的物理内容中可能存在位对齐或其他逻辑表示相同但是物理表示不同的值(比如 true 和 2 或 3,它们在逻辑上都表示”真”,但在物理上两者的表示并不相同)。
与 atomic_compare_exchange_strong 不同,
weak
版本的 compare-and-exchange 操作允许(
spuriously 地
)返回 false(即原子对象所封装的值与参数
expected
的物理内容相同,但却仍然返回 false),不过在某些需要循环操作的算法下这是可以接受的,并且在一些平台下 compare_exchange_weak 的性能更好 。如果 atomic_compare_exchange_weak 的判断确实发生了伪失败(
spurious failures)——
即使原子对象所封装的值与参数
expected
的物理内容相同,但判断操作的结果却为 false,atomic_compare_exchange_weak 函数返回 false,并且参数 expected 的值不会改变。
atomic_compare_exchange_weak_explicit
template (1) |
|
---|---|
overloads (2) |
|
比较并交换被封装的值(weak)与参数 expected 所指定的值是否相等,如果:
- 相等,则用 val 替换原子对象的旧值。
-
不相等,则用原子对象的旧值替换
expected
,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,
expected
中的内容就是原子对象的旧值。
该函数通常会读取原子对象封装的值,如果比较为 true(即原子对象的值等于
expected
),则替换原子对象的旧值,但整个操作是原子的,在某个线程读取和修改该原子对象时,另外的线程不能对读取和修改该原子对象。
内存序(Memory Order)的选择取决于比较操作结果,如果比较结果为 true(即原子对象的值等于
expected
),则选择参数 success 指定的内存序,否则选择参数 failure 所指定的内存序。
注意,该函数直接比较原子对象所封装的值与参数
expected
的物理内容,所以某些情况下,对象的比较操作在使用 operator==() 判断时相等,但 compare_exchange_weak 判断时却可能失败,因为对象底层的物理内容中可能存在位对齐或其他逻辑表示相同但是物理表示不同的值(比如 true 和 2 或 3,它们在逻辑上都表示”真”,但在物理上两者的表示并不相同)。
与 atomic_compare_exchange_strong 不同,
weak
版本的 compare-and-exchange 操作允许(
spuriously 地
)返回 false(即原子对象所封装的值与参数
expected
的物理内容相同,但却仍然返回 false),不过在某些需要循环操作的算法下这是可以接受的,并且在一些平台下 compare_exchange_weak 的性能更好 。如果 atomic_compare_exchange_weak 的判断确实发生了伪失败(
spurious failures)——
即使原子对象所封装的值与参数
expected
的物理内容相同,但判断操作的结果却为 false,atomic_compare_exchange_weak函数返回 false,并且参数 expected 的值不会改变。
对于某些不需要采用循环操作的算法而言, 通常采用 atomic_compare_exchange_strong 更好。另外,该函数的内存序由 sync 参数指定,可选条件如下:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_compare_exchange_strong
template (1) |
|
---|---|
overloads (2) |
|
比较并交换被封装的值(strong)与参数 expected 所指定的值是否相等,如果:
- 相等,则用 val 替换原子对象的旧值。
-
不相等,则用原子对象的旧值替换
expected
,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,
expected
中的内容就是原子对象的旧值。
该函数通常会读取原子对象封装的值,如果比较为 true(即原子对象的值等于
expected
),则替换原子对象的旧值,但整个操作是原子的,在某个线程读取和修改该原子对象时,另外的线程不能对读取和修改该原子对象。
注意,该函数直接比较原子对象所封装的值与参数
expected
的物理内容,所以某些情况下,对象的比较操作在使用 operator==() 判断时相等,但 compare_exchange_weak 判断时却可能失败,因为对象底层的物理内容中可能存在位对齐或其他逻辑表示相同但是物理表示不同的值(比如 true 和 2 或 3,它们在逻辑上都表示”真”,但在物理上两者的表示并不相同)。
与 atomic_compare_exchange_weak 不同, strong版本的 compare-and-exchange 操作不允许(
spuriously 地
)返回 false,即原子对象所封装的值与参数
expected
的物理内容相同,比较操作一定会为 true。不过在某些平台下,如果算法本身需要循环操作来做检查, atomic_compare_exchange_weak 的性能会更好。
因此对于某些不需要采用循环操作的算法而言, 通常采用 atomic_compare_exchange_strong 更好。
atomic_compare_exchange_strong_explicit
template (1) |
|
---|---|
overloads (2) |
|
比较并交换被封装的值(strong)与参数 expected 所指定的值是否相等,如果:
- 相等,则用 val 替换原子对象的旧值。
-
不相等,则用原子对象的旧值替换
expected
,因此调用该函数之后,如果被该原子对象封装的值与参数 expected 所指定的值不相等,
expected
中的内容就是原子对象的旧值。
该函数通常会读取原子对象封装的值,如果比较为 true(即原子对象的值等于
expected
),则替换原子对象的旧值,但整个操作是原子的,在某个线程读取和修改该原子对象时,另外的线程不能对读取和修改该原子对象。
内存序(Memory Order)的选择取决于比较操作结果,如果比较结果为 true(即原子对象的值等于
expected
),则选择参数 success 指定的内存序,否则选择参数 failure 所指定的内存序。
注意,该函数直接比较原子对象所封装的值与参数
expected
的物理内容,所以某些情况下,对象的比较操作在使用 operator==() 判断时相等,但 compare_exchange_weak 判断时却可能失败,因为对象底层的物理内容中可能存在位对齐或其他逻辑表示相同但是物理表示不同的值(比如 true 和 2 或 3,它们在逻辑上都表示”真”,但在物理上两者的表示并不相同)。
与atomic_compare_exchange_weak 不同, strong版本的 compare-and-exchange 操作不允许(
spuriously 地
)返回 false,即原子对象所封装的值与参数
expected
的物理内容相同,比较操作一定会为 true。不过在某些平台下,如果算法本身需要循环操作来做检查, atomic_compare_exchange_weak 的性能会更好。
因此对于某些不需要采用循环操作的算法而言, 通常采用 atomic_compare_exchange_strong 更好。另外,该函数的内存序由 sync 参数指定,可选条件如下:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_fetch_add
template (integral) (1) |
|
---|---|
template (pointer) (2) |
|
overloads (3) |
|
将原子对象的封装值加 val,并返回原子对象的旧值(适用于整形和指针类型的 std::atomic 特化版本),整个过程是原子的。该函数默认内存序为 memory_order_seq_cst。
该函数等价于 std::atomic 对象的atomic::fetch_add和 atomic::operator+= 成员函数。
atomic_fetch_add_explicit
template (integral) (1) |
|
---|---|
template (pointer) (2) |
|
overloads (3) |
|
将原子对象的封装值加 val,并返回原子对象的旧值(适用于整形和指针类型的 std::atomic 特化版本),整个过程是原子的。
该函数等价于 std::atomic 对象的atomic::fetch_add成员函数。sync 参数指定内存序:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_fetch_sub
template (integral) (1) |
|
---|---|
template (pointer) (2) |
|
overloads (3) |
|
将原子对象的封装值减 val,并返回原子对象的旧值(适用于整形和指针类型的 std::atomic 特化版本),整个过程是原子的。
atomic_fetch_sub_explicit
template (integral) (1) |
|
---|---|
template (pointer) (2) |
|
overloads (3) |
|
将原子对象的封装值减 val,并返回原子对象的旧值(适用于整形和指针类型的 std::atomic 特化版本),整个过程是原子的。
该函数等价于 std::atomic 对象的atomic::fetch_sub成员函数。sync 参数指定内存序:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_fetch_and
emplate (integral) (1) |
|
---|---|
overloads (2) |
|
将原子对象的封装值按位与 val,并返回原子对象的旧值(只适用于整型的 std::atomic 特化版本),整个过程是原子的。
atomic_fetch_and_explicit
template (integral) (1) |
|
---|---|
overloads (2) |
|
将原子对象的封装值按位与 val,并返回原子对象的旧值(只适用于整型的 std::atomic 特化版本),整个过程是原子的。
该函数等价于 std::atomic 对象的atomic::fetch_and成员函数。sync 参数指定内存序:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_fetch_or
template (integral) (1) |
|
---|---|
overloads (2) |
|
将原子对象的封装值按位或 val,并返回原子对象的旧值(只适用于整型的 std::atomic 特化版本),整个过程是原子的。
atomic_fetch_or_explicit
template (integral) (1) |
|
---|---|
overloads (2) |
|
A将原子对象的封装值按位或 val,并返回原子对象的旧值(只适用于整型的 std::atomic 特化版本),整个过程是原子的。
该函数等价于 std::atomic 对象的atomic::fetch_or成员函数。sync 参数指定内存序:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
atomic_fetch_xor
template (integral) (1) |
|
---|---|
overloads (2) |
|
将原子对象的封装值按位异或 val,并返回原子对象的旧值(只适用于整型的 std::atomic 特化版本),整个过程是原子的。
atomic_fetch_xor_explicit
template (integral) (1) |
|
---|---|
overloads (2) |
|
将原子对象的封装值按位异或 val,并返回原子对象的旧值(只适用于整型的 std::atomic 特化版本),整个过程是原子的。
该函数等价于 std::atomic 对象的atomic::fetch_xor成员函数。sync 参数指定内存序:
Memory Order 值 | Memory Order 类型 |
---|---|
memory_order_relaxed | Relaxed |
memory_order_consume | Consume |
memory_order_acquire | Acquire |
memory_order_release | Release |
memory_order_acq_rel | Acquire/Release |
memory_order_seq_cst | Sequentially consistent |
与原子对象初始化相关的宏
此外,还有两个宏值得关注,他们分别是:
ATOMIC_VAR_INIT(val)
初始化 std::atomic 对象。
ATOMIC_FLAG_INIT
初始化 std::atomic_flag 对象。