atomic 注释14:类 _Atomic_lock_guard<T>,泛型类 _Atomic_storage<T , u_long_long >及特化版本 _Atomic_storage<T ,1>

(38)类 _Atomic_lock_guard《T》 ,顾名思义,该类是为了防止使用了自旋锁后,忘记释放自旋锁

template <class _Spinlock_t>    // 锁的保卫,以防止忘记释放锁   
class _Atomic_lock_guard
{
private:
    _Spinlock_t& _Spinlock;     // 数据成员是对自旋锁的左值引用

public:
    explicit _Atomic_lock_guard(_Spinlock_t& _Spinlock_) noexcept     // 有参构造函数
        : _Spinlock(_Spinlock_)
    {
        _Atomic_lock_acquire(_Spinlock);  // 直到获得此自旋锁,构造函数才返回
    }

    _Atomic_lock_guard(const _Atomic_lock_guard&) = delete;            // 禁止 copy 构造函数
    _Atomic_lock_guard& operator=(const _Atomic_lock_guard&) = delete; // 禁止 copy 赋值运算符函数

    ~_Atomic_lock_guard() {  _Atomic_lock_release(_Spinlock);  }       // 析构函数,释放自旋锁
};

(39) 重要基类 _Atomic_storage<T , unsigned long long >,先通过下面的简化代码,显示本模板类的作用。为 atomic《T》 类存储数据。所以阅读 atomic 前需要阅读本类来了解 atomic 里的数据成员是怎么被存储与管理的:

template <class _Ty>   // 对齐sizeof (T);x86堆栈在4字节边界上对齐8字节对象
struct _Atomic_padded
{   alignas(sizeof(_Ty)) mutable _Ty _Value;  };

template <class _Ty>
struct _Atomic_storage_types  {
    using _TStorage = _Atomic_padded<_Ty>;
    using _Spinlock = long;
};

template <class _Ty>
struct _Atomic_storage_types<_Ty&>   {
    using _TStorage = _Ty&;
    using _Spinlock = _Smtx_t*; // POINTER TO mutex
};

//-----------------------------------------------------------------------------

template <class _Ty, size_t >
struct _Atomic_storage        // 分析此版本得了
{   _Ty _Storage{};    };

template <class _Ty>
struct _Atomic_storage<_Ty, 1>  // 还有 2 4 8 16 的重载
{   typename _Atomic_storage_types<_Ty>::_TStorage _Storage;   };

template <class _Ty, size_t = sizeof(_Ty)> // 还有 1 2 4 8 的重载,但其泛化版本无定义
struct _Atomic_integral : _Atomic_storage<_Ty> {};

template <class _Ty>  // 本模板作为普通整形 atomic<int> 的父类 ,本类并无数据成员
struct _Atomic_integral_facade : _Atomic_integral<_Ty>{  };

template <class _Ty>  // atomic value
struct atomic : _Choose_atomic_base_t<_Ty>{};

++ 也给出其图片版,看哪个易于阅读:

在这里插入图片描述

(40)接着给出该类的成员函数的测试,以了解这些成员函数的功能

在这里插入图片描述

++ 以及:

在这里插入图片描述

(41)接着给出该类的源代码

template <class _Ty, size_t = sizeof(remove_reference_t<_Ty>)> // 模板类的前向声明,下面要用
struct _Atomic_storage;

template <class _Ty, size_t >  // 第二个普通模板参数是有默认值的
struct _Atomic_storage         // 非类型模板参数,必须在编译时是已知的常量表达式
{
private:
    // 简单情况下 _Spinlock = long 类型。引用情况下 _Spinlock 是 void * 类型。
    mutable typename _Atomic_storage_types<_Ty>::_Spinlock _Spinlock{}; // 定义了一个自旋锁

protected: // 此函是为了初始化 _Ty 是引用类型的情况,调用的函数的定义在本文最上面
    void _Init_spinlock_for_ref() { _Spinlock = __std_atomic_get_mutex(_STD addressof(_Storage)); }

public:
    _Ty _Storage{};              // 原子量要保护的数据成员,是个引用,也可以是一个值,都包括了

    using _TVal = remove_reference_t<_Ty>;

    using _Guard = _Atomic_lock_guard<typename _Atomic_storage_types<_Ty>::_Spinlock>; //锁的 guard

    _Atomic_storage() = default;  // 默认构造函数

    _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) // 有参构造函数
        : _Storage(_Value) { }    

    void notify_one() { __std_atomic_notify_one_indirect(_STD addressof(_Storage)); } // 搭配 wait(..) 使用

    void notify_all() { __std_atomic_notify_all_indirect(_STD addressof(_Storage)); }

    void store(const _TVal _Value, const memory_order _Order = memory_order_seq_cst) // 存入值
    {
        _Check_store_memory_order(_Order); // 允许的写入内存序:relaxed、release、seq_cst
        _Guard _Lock{ _Spinlock };         // 先获取自旋锁,再存入数据,这就是原子量的来源
        _Storage = _Value;
    }

    _TVal load(const memory_order _Order = memory_order_seq_cst) const noexcept // 读取值
    {
        _Check_load_memory_order(_Order);  // 允许的读取内存序:relaxed、acquire、seq_cst
        _Guard _Lock{ _Spinlock };         // 先获取自旋锁,再读取数据
        _TVal _Local(_Storage);
        return _Local;                     // 返回值是值传递
    }
  
    _TVal exchange(const _TVal _Value, const memory_order _Order = memory_order_seq_cst) noexcept
    {
        _Check_memory_order(_Order);       // 要求形参是 0~5 中的任意一种内存序即可
        _Guard _Lock{ _Spinlock };
        _TVal _Result(_Storage);
        _Storage = _Value;
        return _Result;                    // 把新值 _Value 存入本模板中,并把保存的旧值返回
    }

    // 当本类中存储的值   等于形参1 时,把形参 2 的值存入本类;
    // 当本类中存储的值 不等于形参1 时,把本类中的值写入形参 1 。有点指令 cmpxchg 的语义。
    // 返回值表示形参1 与本类中的值是否相等,是则返回 true。
    bool compare_exchange_strong  // 注意:形参1 是左值引用,对左值引用取地址返回的是原始值的地址
    (_TVal& _Expected, const _TVal _Desired, const memory_order _Order = memory_order_seq_cst)
    {
        _Check_memory_order(_Order);
        const auto _Storage_ptr  = _STD addressof(_Storage ); // 取本类中数据成员的地址
        const auto _Expected_ptr = _STD addressof(_Expected);
        bool _Result;

        _Guard _Lock{ _Spinlock };         // 取得自旋锁

        _Result = _CSTD memcmp(_Storage_ptr, _Expected_ptr, sizeof(_TVal)) == 0;

        if (_Result) 
            _CSTD memcpy(_Storage_ptr , _STD addressof(_Desired), sizeof(_TVal));
        else 
            _CSTD memcpy(_Expected_ptr, _Storage_ptr, sizeof(_TVal));
        
        return _Result;
    }

    void wait(_TVal _Expected, memory_order = memory_order_seq_cst) const noexcept // 值不等于形参 1 才返回
    {
        const auto _Storage_ptr  = _STD addressof(_Storage );
        const auto _Expected_ptr = _STD addressof(_Expected);
        for (;;)                            // wait ()被 nofify ()唤醒后,若原子量的值等于形参 1,还是不会返回的。
        {
            {   _Guard _Lock{ _Spinlock };  // 取得自旋锁

                if (_CSTD memcmp(_Storage_ptr, _Expected_ptr, sizeof(_TVal)) != 0)   return;
            } 

            __std_atomic_wait_indirect(_Storage_ptr, _Expected_ptr, sizeof(_TVal), &_Spinlock,
                &_Atomic_wait_compare_non_lock_free<decltype(_Spinlock)>, _Atomic_wait_no_timeout);
        }
    }

};

(42)接着介绍此类的特化版本,具有更高的效率,也省去了该泛型类包含的自旋锁。先对特化版本的一个成员函数进行测试,确定其返回值:

在这里插入图片描述

(43)接着介绍该类 _Atomic_storage《T , unsgned long_long 》的特化版本之一: _Atomic_storage《T , 1》。该模板类有对常见数据类型有多个特化版本,接着一一介绍。经仔细查看与测试,所有同名成员函数的语义都没有发生改变

template <class _Ty> // lock-free using 1-byte intrinsics,无锁,使用 1 字节内置函数
struct _Atomic_storage<_Ty, 1>   // 本特化版本,缺少了内置的自旋锁的数据成员,效率更高
{   
    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>;

    _Atomic_storage() = default;                                                 // 默认构造函数

    // non-atomically initialize this atomic
    _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) // 有参构造函数 
        : _Storage{_Value} { }

// template <class _Ty, class _Value_type>   本函数会让本线程睡眠等待,直到形参 1 和 2 不等才返回
// void _Atomic_wait_direct                  更准确的描述是等待原子量(形参1 ) 发生变化后才返回
// ( _Atomic_storage<_Ty>* this, _Value_type expected_bytes, memory_order order)
    // 所以,本成员函数的语义是等待本类的数据成员与形参 1 不等才返回。 
    void wait(const _TVal _Expected, const memory_order _Order = memory_order_seq_cst)
    {
        _Atomic_wait_direct(this, _Atomic_reinterpret_as<char>(_Expected), _Order);
    }

    void notify_one() { __std_atomic_notify_one_direct(_STD addressof(_Storage)); }

    void notify_all() { __std_atomic_notify_all_direct(_STD addressof(_Storage)); }

/*
template <class _Integral, class _Ty> // 本函返回形参引用的原始数据的地址
volatile _Integral* _Atomic_address_as(_Ty& _Source)  // 本函数是精简版
{   return &reinterpret_cast<volatile _Integral&>(_Source);   }
*/
    void store(const _TVal _Value) noexcept // store with sequential consistency 函数重载
    { 
        const auto _Mem      = _Atomic_address_as<char>(_Storage);

        const char _As_bytes = _Atomic_reinterpret_as<char>(_Value);

        (void) _InterlockedExchange8(_Mem, _As_bytes);
    }

    void store(const _TVal _Value, const memory_order _Order) noexcept // store with given memory order
    { 
        const auto _Mem      = _Atomic_address_as<char>(_Storage);
        const char _As_bytes = _Atomic_reinterpret_as<char>(_Value);
        switch (_Order)
        {
        case memory_order_relaxed:
            __iso_volatile_store8(_Mem, _As_bytes);     return;
        case memory_order_release:
            _Compiler_or_memory_barrier(); // _Compiler_or_memory_barrier() = _Compiler_barrier()
            __iso_volatile_store8(_Mem, _As_bytes);
            return;
        default:
        case memory_order_consume:         // 以下几种内存序违法
        case memory_order_acquire:
        case memory_order_acq_rel:
            _INVALID_MEMORY_ORDER;
            // [[fallthrough]];
        case memory_order_seq_cst:    store(_Value);     return;
        }
    }

    //************

    _TVal load() const noexcept  // load with sequential consistency 函数重载,返回值是值传递
    { 
        const auto _Mem = _Atomic_address_as<char>(_Storage); // 获得本类中数据成员的地址

        char _As_bytes  = __iso_volatile_load8(_Mem);

        _Compiler_or_memory_barrier(); //= _Compiler_barrier() 插入内存栅栏

        return reinterpret_cast<_TVal&>(_As_bytes);
    }

    _TVal load(const memory_order _Order) const noexcept  // load with given memory order
    { 
        const auto _Mem = _Atomic_address_as<char>(_Storage);

        char _As_bytes  = __iso_volatile_load8(_Mem);

        _Load_barrier(_Order);         //  检查并根据形参内存序的级别,设置内存栅栏

        return reinterpret_cast<_TVal&>(_As_bytes);
    }

    //*************

    // exchange with given memory order 按指定内存序,把形参 1 的值存入本类中
    _TVal exchange(const _TVal _Value, const memory_order _Order = memory_order_seq_cst) 
    {      
        char _As_bytes;

        _ATOMIC_CHOOSE_INTRINSIC(_Order, _As_bytes, _InterlockedExchange8, // 由宏函数完成实际的内存交换
            _Atomic_address_as<char>(_Storage), _Atomic_reinterpret_as<char>(_Value));

        return reinterpret_cast<_TVal&>(_As_bytes); // 经测试,是把本类保存的旧值返回
    }
/* 此宏函数的定义在本头文件的最上面
#define _ATOMIC_CHOOSE_INTRINSIC(_Order, _Result, _Intrinsic, ...) \
    _Check_memory_order(_Order);                                   \
    _Result = _Intrinsic(__VA_ARGS__)
*/

    // 当本类中存储的值   等于形参1 时,把形参 2 的值存入本类;
    // 当本类中存储的值 不等于形参1 时,把本类中的值写入形参 1 。有点指令 cmpxchg 的语义。
    // 返回值表示形参1 与本类中的值是否相等,是则返回 true。
    bool compare_exchange_strong    // CAS with given memory order
    (_TVal& _Expected, const _TVal _Desired, const memory_order _Order = memory_order_seq_cst)
    { 
        char _Expected_bytes = _Atomic_reinterpret_as<char>(_Expected); // 形参 1 是左值引用

        char _Prev_bytes; // 下面宏函数里 函_InterlockedCompareExchange8() 的返回值

        // 经测试,函 _InterlockedCompareExchange8() 总返回其形参1 的原值。这里则是本类中的数据成员原始值
        _ATOMIC_CHOOSE_INTRINSIC(_Order, _Prev_bytes, _InterlockedCompareExchange8, // 包含的函数变了
            _Atomic_address_as<char>(_Storage), _Atomic_reinterpret_as<char>(_Desired), _Expected_bytes);

        if (_Prev_bytes == _Expected_bytes)   return true;
        
        reinterpret_cast<char&>(_Expected) = _Prev_bytes; // 形参1 是左值引用

        return false;
    }

};

(44)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值