内存模型与内存序
std::atomic保证
struct atomic : _Choose_atomic_base_t<_Ty> { atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; _Ty operator=(const _Ty _Value) noexcept { this->store(_Value); return _Value; }
void store(const _Ty _Value) volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); const_cast<atomic*>(this)->_Base::store(_Value); }
void store(const _Ty _Value, const memory_order _Order) volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); const_cast<atomic*>(this)->_Base::store(_Value, _Order); }
_NODISCARD _Ty load() const volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<const atomic*>(this)->_Base::load(); }
_NODISCARD _Ty load(const memory_order _Order) const volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<const atomic*>(this)->_Base::load(_Order); }
using _Base::exchange; _Ty exchange(const _Ty _Value) volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<atomic*>(this)->_Base::exchange(_Value); }
_Ty exchange(const _Ty _Value, const memory_order _Order) volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<atomic*>(this)->_Base::exchange(_Value, _Order); }
#if _HAS_CXX20 using _Base::wait; void wait(const _Ty _Expected, const memory_order _Order = memory_order_seq_cst) const volatile noexcept { const_cast<const atomic*>(this)->_Base::wait(_Expected, _Order); }
using _Base::notify_one; void notify_one() volatile noexcept { const_cast<atomic*>(this)->_Base::notify_one(); }
using _Base::notify_all; void notify_all() volatile noexcept { const_cast<atomic*>(this)->_Base::notify_all(); } #endif
operator _Ty() const volatile noexcept { static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return this->load(); }
operator _Ty() const noexcept { return this->load(); } };
|
原子性
原子性的意思是,读写该变量的操作是原子的。原子性通过store和load函数内部保证,operator=内部实际上调用了store。
#include <atomic> #include <thread> #include <iostream>
std::atomic<int> a;
void increase() { for (size_t i = 0; i < 10000; i++) a++; }
int main() { std::thread t1(increase); std::thread t2(increase); t1.join(); t2.join(); std::cout << a;
return 0; }
|
store
负责原子地写入数据。
load
负责原子的读取数据。
fetch_add
原子自增。
fetch_sub
原子自减。
compare_exchange_strong
用于自定义原子操作。
template <typename T> void fetch_sqr(std::atomic<T> data) { do { auto old_data = data.load(); auto new_data = old_data* old_data; } while(!data.compare_exchange_strong(old_data, new_data)); }
|
内存序
#if _HAS_CXX20 _EXPORT_STD enum class memory_order : int { relaxed, consume, acquire, release, acq_rel, seq_cst,
memory_order_relaxed = relaxed, memory_order_consume = consume, memory_order_acquire = acquire, memory_order_release = release, memory_order_acq_rel = acq_rel, memory_order_seq_cst = seq_cst }; _EXPORT_STD inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; _EXPORT_STD inline constexpr memory_order memory_order_consume = memory_order::consume; _EXPORT_STD inline constexpr memory_order memory_order_acquire = memory_order::acquire; _EXPORT_STD inline constexpr memory_order memory_order_release = memory_order::release; _EXPORT_STD inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; _EXPORT_STD inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; #else enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst }; #endif
|
-
relaxed:无内存序
-
seq_cst:顺序一致性
-
consume:与该变量有关的指令不会重排
-
acquire:下方的指令不会排序到上方
-
release:上方的指令不会排序到下方
-
acq_rel:双侧屏障
验证模型
线程池(避免验证中频繁创建和释放线程开销)
使用MSVC的std::async(底层实现使用了线程池技术)。
测试基类模板
struct Test { virtual void t1() = 0; virtual void t2() = 0; virtual void reset() = 0; virtual bool test() = 0; virtual ~Test() = default; };
template <typename T> class TestModel { T t; public: void run() { const size_t thread_count = std::thread::hardware_concurrency(); T testInstance; size_t err_num = 0; for (size_t i = 0; i < 10000; ++i) { std::vector<std::future<void>> futures;
testInstance.reset(); futures.emplace_back(std::async(std::launch::async, &T::t2, &testInstance)); futures.emplace_back(std::async(std::launch::async, &T::t1, &testInstance)); for (auto& future : futures) { future.get(); }
if (!testInstance.test()) { err_num++; } }
std::cout << "执行完成,错误数量:" << err_num << std::endl; } };
|
核心测试代码
#define in_atomic 0
struct TestStr :Test { #if in_atomic std::atomic<bool> flag; #else bool flag; #endif std::string str; bool res; virtual void t1() override { str = "Hello"; #if in_atomic flag.store(true); #else flag = true; #endif
}
virtual void t2() override { #if in_atomic while (flag.load() == false); #else while (flag == false) std::this_thread::yield();; #endif if (str == "Hello") res = true; ss << "string is " << str << '\n'; }
virtual void reset() override { flag = false; res = false; str.clear(); }
virtual bool test() override { return res; } };
int main() { TestModel<TestStr> t; t.run();
return 0; }
|
易错问题
data = data + 1
此操作并非原子操作,因为实际上是两步,分别保证原子性,但不保证合在一起的原子性:
auto data_new = data.load() + 1; data.store(data_new);
|
正确做法:使用重载的operator++运算符。