<mutex>注释3:全局 lock ()、try_lock (),类型转换运算符 operator bool (),函 call_once (...) 的源码及底层依赖的函数及举例,

(15) 可以获取多个锁而不会陷入死锁的 全局函数 lock ( , ) ,实现的依赖的核心函数是 mutex . try_lock () :

template <class... _LockN>  // 该函数非常复杂,略,以后补充。但意思目前已经到了
int _Lock_attempt(const int _Hard_lock, _LockN&... _LkN) {  return 3;  } 

template <class _Lock0, class _Lock1> // 返回值的意思是,若加锁失败,则需要尝试重新加锁,故返回 true。
bool _Lock_attempt_small(_Lock0& _Lk0, _Lock1& _Lk1)  // 所以,若加锁成功则本函返回 false
{   // 尝试锁定2个锁,首先锁定_Lk0,然后尝试锁定_Lk1。返回是否再次trv
    // attempt to lock 2 locks, by first locking _Lk0, and then trying to lock _Lk1 
    // returns whether to try again。

    _Lk0.lock();
    _TRY_BEGIN           //  try {
    if (_Lk1.try_lock()) //     if (_Lk1.try_lock()) // 本函加锁成功返 T,锁忙碌返 F
        return false;    //         return false;

    _CATCH_ALL           //  } catch (...) {   // 也可能没有错误,捕捉不到错误,不需终止进程
    _Lk0.unlock();       //     _Lk0.unlock();
    _RERAISE;            //     throw;
    _CATCH_END           //  }

    _Lk0.unlock();       //  因为加锁失败,获得的 LK0 锁也释放掉
    _STD this_thread::yield(); // // 使本线程让出 CPU
    return true;         // true 表示本线程再次获得运行时需再次尝试获取这俩锁
}

template <class _Lock0, class _Lock1, class _Lock2, class... _LockN>
void _Lock_nonmember1(_Lock0& _Lk0, _Lock1& _Lk1, _Lock2& _Lk2, _LockN&... _LkN)
{   // 函数重载的复杂情况 lock 3 or more locks, without deadlock
    int _Hard_lock = 0;
    while (_Hard_lock != -1) 
        _Hard_lock = _Lock_attempt(_Hard_lock, _Lk0, _Lk1, _Lk2, _LkN...);
}

template <class _Lock0, class _Lock1> // 这是重载的简单情况
void _Lock_nonmember1(_Lock0& _Lk0, _Lock1& _Lk1)
{   // 锁 2 锁,没有死锁,特殊情况下更好的 codegen 和 redu 通用元编程
    while ( _Lock_attempt_small(_Lk0, _Lk1) && _Lock_attempt_small(_Lk1, _Lk0)) {}  
    // 函数 _Lock_attempt_small 加锁成功则返回 false ,加锁失败返回 true
}

template <class _Lock0, class _Lock1, class... _LockN> // lock multiple locks, without deadlock
void lock(_Lock0& _Lk0, _Lock1& _Lk1, _LockN&... _LkN) // 锁定多个锁,无死锁
{   //看源码,本函只有在获取了所有锁之后,才会返回。
    _Lock_nonmember1(_Lk0, _Lk1, _LkN...);
}   //本函数的实现灵魂是调用 mutex.try_lock(),该函数不会陷入睡眠等待

(16) 全局不阻塞线程拿到多个锁的函数 try_lock (…)本函尝试加锁成功,返回 -1 。锁忙碌则释放所有的锁,返回0 或 1:

template <class... _LockN>  // 此函数的调用链一如既往的复杂,暂时略。以后看情能看懂的话况再补充
int _Try_lock_range(const int _First, const int _Last, _LockN&... _LkN) { return -1; }

template <class _Lock0, class _Lock1, class _Lock2, class... _LockN>
int _Try_lock1(_Lock0& _Lk0, _Lock1& _Lk1, _Lock2& _Lk2, _LockN&... _LkN) 
{   // try to lock 3 or more locks
    return _Try_lock_range(0, sizeof...(_LockN) + 3, _Lk0, _Lk1, _Lk2, _LkN...);
}

template <class _Lock0, class _Lock1>  // 函数的重载
int _Try_lock1(_Lock0& _Lk0, _Lock1& _Lk1) 
{
    if (!_Lk0.try_lock())  // 此函数 try 加锁成功则返回 true,锁忙碌则返回 false
        return 0;

    _TRY_BEGIN              // try {
    if (!_Lk1.try_lock()) { //     if (!_Lk1.try_lock()) { 
        _Lk0.unlock();      //          _Lk0.unlock();
        return 1;           //          return 1;
    }                       //     }
    _CATCH_ALL              // } catch (...) { // 也可能没有错误,捕捉不到错误,不需终止进程
        _Lk0.unlock();      //     _Lk0.unlock();
    _RERAISE;               //     throw;
    _CATCH_END              // }

    return -1;
}

template <class _Lock0, class _Lock1, class... _LockN>
int try_lock(_Lock0& _Lk0, _Lock1& _Lk1, _LockN&... _LkN)
{   // try to lock multiple locks
    return _Try_lock1(_Lk0, _Lk1, _LkN...);
}   // 本函尝试加锁成功,返回 -1 。锁忙碌则释放所有的锁,返回0 或 1

(17) 类型转换运算符 operator bool (),在 unique_lock 的源代码里,出现了类型转换函数,学习一下:

在这里插入图片描述

++可见此类型转换运算符函数的书写,没有函数返回值。 举例测试一下:

在这里插入图片描述

++ 以及:

在这里插入图片描述

++ 以及:

在这里插入图片描述

++ 对于 unique_lock 的学习,涉及到线程同步里对时间量的使用,以后再总结与完善所有的源代码。

(18) 函 call_once (…) 的源码 ,这是正确使用该函数的理论依据,加锁互斥的功能,调用了更底层的系统函数:

extern "C"  int __std_init_once_begin_initialize(
    void** _LpInitOnce, unsigned long _DwFlags, int* _FPending, void** _LpContext) noexcept;

// 这两个系统函数都是成功执行返回 true,失败返回 false。 参数名可以见名知意。

// 系统函数__std_init_once_complete(&_Once._Opaque, 控制标志, 可选的上下文环境)
extern "C" int __std_init_once_complete(
     void** _LpInitOnce, unsigned long _DwFlags, void* _LpContext) noexcept;

// #define RTL_RUN_ONCE_INIT_FAILED    0x00000004UL
// #define INIT_ONCE_INIT_FAILED       RTL_RUN_ONCE_INIT_FAILED
_INLINE_VAR constexpr unsigned long _Init_once_init_failed = 0x4UL; // 初始化失败的标志

struct once_flag  // opaque不透明的 data structure for call_once()
{
    void* _Opaque; // 含有一个指针类型的数据成员

    once_flag() noexcept : _Opaque(nullptr) {} // 默认构造函数

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

struct _Init_once_completer // 类似智能指针或 lock_guard,用于析构上面的 once_flag 对象
{                           // 本类型的对象是定义在 call_once(...) 函数内的局部对象
    once_flag& _Once;       // 数据成员,对 once_flag 类型的数据的引用
    unsigned long _DwFlags;

    ~_Init_once_completer() // 析构函数
    {   
        if ( __std_init_once_complete(&_Once._Opaque, _DwFlags, nullptr) == 0 ) 
            _CSTD abort();  // __declspec(noreturn) void __cdecl abort(void);
    }
};

// 在进程全局里生成 once_flag 对象,这里使用其 once_flag对象 的左值引用
template <class _Fn, class... _Args>  // call 函数  _Fx(_Ax...) once,只调用形参中的函数一次
void call_once (once_flag&  _Once, _Fn&& _Fx, _Args&&... _Ax)  // 这一行最重要
noexcept(noexcept(_STD invoke(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...))) 
{
    int _Pending;

    // 看意思,函数仅可以被执行一次的设置,是在这里执行的,这里的 nullptr 也是可选的上下文环境
    if ( __std_init_once_begin_initialize(&_Once._Opaque, 0, &_Pending, nullptr) == 0 )
        _CSTD abort(); // __declspec(noreturn) void __cdecl abort(void);

    if (_Pending != 0) // unsigned long _Init_once_init_failed = 0x4UL; 
    {       
        _Init_once_completer _Op{_Once, _Init_once_init_failed}; // 本函数内定义的局部变量

        _STD invoke(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
        _Op._DwFlags = 0;
    }
}

(19) 关于 canll_ince ( … ) 调用的系统函数的描述,谢谢网上的资料与老师:

在这里插入图片描述
在这里插入图片描述

++ 以及函数 InitOnceComplete (…) 函数原型的解释

在这里插入图片描述
在这里插入图片描述

++ 代码演示:

#include <windows.h>
#include <iostream>

INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT;

BOOL CALLBACK InitFunction(PINIT_ONCE pInitOnce, PVOID pParameter, PVOID* lpContext) 
{
    std::cout << "Initializing..." << std::endl;
    // 在这里执行初始化代码
    return TRUE; // 返回 TRUE 表示初始化成功
}

int main()
{
    BOOL isInitialized = FALSE;

    // 尝试进行一次性初始化
    isInitialized = InitOnceExecuteOnce(&g_InitOnce, InitFunction, NULL, NULL);

    if (isInitialized) {
        std::cout << "Initialization completed successfully." << std::endl;
    } else {
        std::cout << "Initialization failed." << std::endl;
    }

    return 0;
}

++ 简评:

在这里插入图片描述

(20) 全局函数 call_once (…) 的使用举例

在这里插入图片描述

(21)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值