(47)接着继续学习该类的特化版本 _Atomic_storage<_Ty&, 16>,原子地管理 16 字节的数据。但注意形参 1 是左值引用。先给出一个测试,以确定其中一个成员函数的功能:
++ 接着给出其源代码:
#ifdef _WIN64 // 本特化版本值存在于 win64 平台上。
template <class _Ty> // lock-free using 16-byte intrinsics
struct _Atomic_storage<_Ty&, 16> // 无锁,使用 16 字节内置函数
{
struct _Int128 { alignas(16) long long _Low; long long _High; }; // 类内定义的类
typename _Atomic_storage_types<_Ty&>::_TStorage _Storage; // 本类的数据成员将是左值引用
/*
template <class _Ty> // 这个特化版本的数据成员的定义,也不同于其泛化版本
struct _Atomic_padded { alignas(sizeof(_Ty)) mutable _Ty _Value; };
template <class _Ty>
struct _Atomic_storage_types { using _TStorage = _Atomic_padded<_Ty>; };
template <class _Ty>
struct _Atomic_storage_types<_Ty&> { using _TStorage = _Ty&; };
*/
using _TVal = remove_reference_t<_Ty&>; // 对于左值引用,_TVal 仍然是基础无引用类型
_Atomic_storage() = default; // 默认构造函数
// non-atomically initialize this atomic
_Atomic_storage(conditional_t<is_reference_v<_Ty&>, _Ty&, const _TVal> _Value) // 有参构造函数
: _Storage{_Value} {}
// 本函数的语义不变:仍然是本类中的数据成员的值不等于形参1 才返回
void wait(_TVal _Expected, memory_order _Order = memory_order_seq_cst) const noexcept
{
const auto _Storage_ptr = _STD addressof(_Storage) ;
const auto _Expected_ptr = _STD addressof(_Expected);
_Int128 _Expected_bytes = reinterpret_cast<const _Int128&>(_Expected);
for (;;)
{
const _TVal _Observed = load(_Order);
_Int128 _Observed_bytes = reinterpret_cast<const _Int128&>(_Observed);
if (_Observed_bytes._Low != _Expected_bytes._Low || _Observed_bytes._High != _Expected_bytes._High)
return;
__std_atomic_wait_indirect(_Storage_ptr, _Expected_ptr, sizeof(_TVal), nullptr,
&_Atomic_wait_compare_16_bytes, _Atomic_wait_no_timeout);
}
}
void notify_one() { __std_atomic_notify_one_indirect(_STD addressof(_Storage)); }
void notify_all() { __std_atomic_notify_all_indirect(_STD addressof(_Storage)); }
//**********************
// 本函数的语义不同于 8 字节以下版本的语义。 本函没有比较的功能,只做交换。
// 本函中形参1 与 2 的值是相同的。
// 本函的功能就是把形参 1 的值设置为本类的数据成员,并把本类中原来的值由形参 1 带回。
// 本函对 16 字节交换成功返回 true , 失败返回 false 。
bool compare_exchange_strong // CAS with given memory order 本函数被下面的成员函数调用
(_TVal& _Expected, const _TVal _Desired, const memory_order _Order = memory_order_seq_cst)
{
_Int128 _Desired_bytes{}; // 从上下文看,此函数的形参1 与 2 是相等的。
_CSTD memcpy(&_Desired_bytes, _STD addressof(_Desired), sizeof(_TVal));
_Int128 _Expected_temp{};
_CSTD memcpy(&_Expected_temp, _STD addressof(_Expected), sizeof(_TVal));
unsigned char _Result; (void)_Order;
//宏函数 _STD_COMPARE_EXCHANGE_128 = __std_atomic_compare_exchange_128,在本文件上面
//结合上下猜测,函 __std_atomic_compare_exchange_128(..) 的返回值表 16 字节的原子交换操作是否成功;
//交换成功返回 true = 1 , 失败未交换返回 false = 0
//该函数是把其形参1 中的值与形参4 中的值进行原子交换。形参 2与 3 表示形参4 中的值。
_Result = _STD_COMPARE_EXCHANGE_128 ( &reinterpret_cast<long long&>(_Storage),
_Desired_bytes._High, _Desired_bytes._Low, &_Expected_temp._Low);
if (_Result == 0) // 因为 16 字节的原子交换失败,恢复形参 1 里的值
_CSTD memcpy(_STD addressof(_Expected), &_Expected_temp, sizeof(_TVal));
return _Result != 0;
}
_TVal exchange(const _TVal _Value) noexcept // exchange with sequential consistency 函数重载
{
_TVal _Result{ _Value };
while ( !compare_exchange_strong(_Result, _Value) ) {}// keep trying
return _Result;
}
_TVal exchange(const _TVal _Value, const memory_order _Order) noexcept // exchange with given memory order
{
_TVal _Result{ _Value };
while (!compare_exchange_strong(_Result, _Value, _Order)) {} // keep trying
return _Result;
}
//***********************
// store with sequential consistency
void store(const _TVal _Value) noexcept { (void) exchange(_Value); } // 函数重载
void store(const _TVal _Value, const memory_order _Order) noexcept // store with given memory order
{
_Check_store_memory_order(_Order);
(void) exchange(_Value, _Order);
}
//*********************
_TVal load() const noexcept // load with sequential consistency
{
long long* const _Storage_ptr = // 把 16 字节结构体的地址作为 long long 类型的地址
const_cast<long long*>(_Atomic_address_as<const long long>(_Storage));
_Int128 _Result{}; // atomic CAS 0 with 0
//此函数交换形参 1 与 4 中的值, 形参2与3表示形参 4 中的值。交换成功返回 true。
(void) _STD_COMPARE_EXCHANGE_128(_Storage_ptr, 0, 0, &_Result._Low);
return reinterpret_cast<_TVal&>(_Result);
}
/*
template <class _Integral, class _Ty> // 本函返回形参引用的原始数据的地址
volatile _Integral* _Atomic_address_as(_Ty& _Source) // 本函数是精简版
{ return &reinterpret_cast<volatile _Integral&>(_Source); }
*/
_TVal load(const memory_order _Order) const noexcept // load with given memory order
{
_Check_load_memory_order(_Order);
return load();
}
};
#endif // _WIN64
(48)上面介绍的 _Atomic_storage《 T,size_t 》 系列,是存储了一个数据,并完成了原子性的读取和赋值该数据。接下来,介绍该类的子类 _Atomic_integral《 T, size_t 》 系列,又增加了新的成员函数,以支持对整数的原子操作,原子性的完成整数运算。先介绍其中被调用的一个 windows 平台的系统函数,是这些操作系统的内部函数的支持,才完成了 STL 库的 atomic 类的多线程中的运算定义。
++ 以下是一个简单的示例,展示了如何使用 _InterlockedExchangeAdd8 来安全地增加一个全局计数器的值:
#include <windows.h>
#include <stdio.h>
#pragma intrinsic(_InterlockedExchangeAdd8)
volatile BYTE counter = 0; // 该全局量被 volatile 修饰
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
for (int i = 0; i < 1000; ++i) { // 原子地增加计数器的值
SHORT oldValue = _InterlockedExchangeAdd8((volatile BYTE*)&counter, 1);
// 这里可以添加一些代码来处理 oldValue,但在这个例子中我们仅仅增加计数器
}
return 0;
}
int main() {
HANDLE hThreads[2]; // 建立了两个线程来同时增加全局量的值。
hThreads[0] = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
hThreads[1] = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
// 输出最终计数器的值
printf("Final counter value: %d\n", counter);
return 0;
}
(49)
谢谢