内存模型与内存序

内存模型与内存序

std::atomic保证

  • 原子性:对一个变量操作期间,保证其它线程不对该变量进行操作

  • 内存序:构造一个事件的发生先后的顺序关系。

struct atomic : _Choose_atomic_base_t<_Ty> { // atomic value
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 // _HAS_CXX20

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,

// LWG-3268
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 // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst
};
#endif // ^^^ !_HAS_CXX20 ^^^
  • 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++运算符。

data++;