<mutex>注释 8:全局函 try_lock (),lock (),模板类 scoped_lock<T...>,函 call_once (), condition_variable 源码及测试举例

(37) 全局函 try_lock () 及其源码

在这里插入图片描述

++ 可见,其返回值的 -1 更有参考意义。该函数可以对任意多个锁加锁,使用了可变参数包的复杂语法。理解简单情形即可,复杂的重载形式,以后再说,接着给出其所有源码:

template <size_t... _Indices, class... _LockN> // 这部分复杂的先暂时不看了
void _Lock_from_locks(const int _Target, index_sequence<_Indices...>, _LockN&... _LkN)  // lock _LkN[_Target]
{
    int _Ignored[] = {(
        (static_cast<int>(_Indices) == _Target ? 
                            (void) _LkN.lock() :
                                          void()
            ), 0
        )...};
    (void) _Ignored;
}

template <size_t... _Indices, class... _LockN>
bool _Try_lock_from_locks(
    const int _Target, index_sequence<_Indices...>, _LockN&... _LkN) { // try to lock _LkN[_Target]
    bool _Result{};
    int _Ignored[] = {((static_cast<int>(_Indices) == _Target ? (void) (_Result = _LkN.try_lock()) : void()), 0)...};
    (void) _Ignored;
    return _Result;
}

template <size_t... _Indices, class... _LockN>
void _Unlock_locks(const int _First, const int _Last, index_sequence<_Indices...>, _LockN&... _LkN) noexcept
/* terminates */ {
    // unlock locks in _LkN[_First, _Last)
    int _Ignored[] = {
        ((_First <= static_cast<int>(_Indices) && static_cast<int>(_Indices) < _Last ? (void) _LkN.unlock() : void()),
            0)...};
    (void) _Ignored;
}

template <class... _LockN>
int _Try_lock_range(const int _First, const int _Last, _LockN&... _LkN) 
{
    using _Indices = index_sequence_for<_LockN...>;
    int _Next      = _First;
    _TRY_BEGIN
    for (; _Next != _Last; ++_Next) 
        if (!_Try_lock_from_locks(_Next, _Indices{}, _LkN...))  // try_lock failed, backout
        { 
            _Unlock_locks(_First, _Next, _Indices{}, _LkN...);
            return _Next;
        }
    _CATCH_ALL
    _Unlock_locks(_First, _Next, _Indices{}, _LkN...);
    _RERAISE;
    _CATCH_END

    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

(38) 全局函数 lock (),根据源码,该函数会在所有的锁都被本线程锁定后,才会返回


/*
template <class _Lock0, class _Lock1, class _Lock2, class... _LockN> // lock 3 or more locks, without deadlock
void _Lock_nonmember1(_Lock0& _Lk0, _Lock1& _Lk1, _Lock2& _Lk2, _LockN&... _LkN)
{   
    int _Hard_lock = 0;
    while (_Hard_lock != -1) 
        _Hard_lock = _Lock_attempt(_Hard_lock, _Lk0, _Lk1, _Lk2, _LkN...);
}
*/
template <class... _LockN> // 该函数不看了,所有注释也一并保留
int _Lock_attempt(const int _Hard_lock, _LockN&... _LkN) 
{   // attempt to lock 3 or more locks, starting by locking _LkN[_Hard_lock] and trying to lock the rest
    
    using _Indices = index_sequence_for<_LockN...>;
/*
template <class _Ty, _Ty... _Vals>   // sequence of integer parameters
struct integer_sequence { 	using value_type = _Ty;  };

template <class _Ty, _Ty _Size>
using make_integer_sequence = __make_integer_seq<integer_sequence, _Ty, _Size>;

template <size_t _Size>
using make_index_sequence = make_integer_sequence<size_t, _Size>;

template <class... _Types>
using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
*/
    _Lock_from_locks(_Hard_lock, _Indices{}, _LkN...);
/*
template <size_t... _Indices, class... _LockN>
void _Lock_from_locks(const int _Target, index_sequence<_Indices...>, _LockN&... _LkN)  // lock _LkN[_Target]
{
    int _Ignored[] = {(
        (static_cast<int>(_Indices) == _Target ?
                            (void) _LkN.lock() :
                                          void()
            ), 0
        )...};

    (void) _Ignored;
}
*/
    int _Failed        = -1;
    int _Backout_start = _Hard_lock; // that is, unlock _Hard_lock

    _TRY_BEGIN
    _Failed = _Try_lock_range(0, _Hard_lock, _LkN...);
/*
template <class... _LockN>
int _Try_lock_range(const int _First, const int _Last, _LockN&... _LkN)
{
    using _Indices = index_sequence_for<_LockN...>;
    int _Next      = _First;
    _TRY_BEGIN
    for (; _Next != _Last; ++_Next)
        if (!_Try_lock_from_locks(_Next, _Indices{}, _LkN...))  // try_lock failed, backout
        {
            _Unlock_locks(_First, _Next, _Indices{}, _LkN...);
            return _Next;
        }
    _CATCH_ALL
    _Unlock_locks(_First, _Next, _Indices{}, _LkN...);
    _RERAISE;
    _CATCH_END

    return -1;
}
*/
    if (_Failed == -1)
    {
        _Backout_start = 0; // that is, unlock [0, _Hard_lock] if the next throws
        _Failed        = _Try_lock_range(_Hard_lock + 1, sizeof...(_LockN), _LkN...);
        if (_Failed == -1)  // we got all the locks
            return -1;
    }
    _CATCH_ALL
    _Unlock_locks(_Backout_start, _Hard_lock + 1, _Indices{}, _LkN...);
    _RERAISE;
    _CATCH_END

    // we didn't get all the locks, backout
    _Unlock_locks(_Backout_start, _Hard_lock + 1, _Indices{}, _LkN...);
    _STD this_thread::yield();
    return _Failed;
}


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(),该函数不会陷入睡眠等待

(39)模板类 scoped_lock <T…>,该类似乎可以管理多个锁,没仔细看,以后再学一学:

#if _HAS_CXX17
template <class... _Mutexes>
class _NODISCARD scoped_lock  // 这里似乎是以一个类的方式,来管理多个锁
{   // class with destructor that unlocks mutexes
private:
    tuple<_Mutexes&...> _MyMutexes;
public:
    // construct and lock
    explicit scoped_lock(_Mutexes&... _Mtxes) : _MyMutexes(_Mtxes...) {  _STD lock(_Mtxes...); }

    // construct but don't lock
    explicit scoped_lock(adopt_lock_t, _Mutexes&... _Mtxes) : _MyMutexes(_Mtxes...) {}

    ~scoped_lock() noexcept 
    {
        _STD apply([](_Mutexes&... _Mtxes) { (..., (void)_Mtxes.unlock()); }, _MyMutexes);
    }

    scoped_lock(const scoped_lock&) = delete;
    scoped_lock& operator=(const scoped_lock&) = delete;
};

template <class _Mutex>
class _NODISCARD scoped_lock<_Mutex> 
{
private:
    _Mutex& _MyMutex;
public:
    using mutex_type = _Mutex;

    // construct and lock
    explicit scoped_lock(_Mutex& _Mtx) : _MyMutex(_Mtx) { _MyMutex.lock(); }

    // construct but don't lock
    explicit scoped_lock(adopt_lock_t, _Mutex& _Mtx) : _MyMutex(_Mtx) {} 

    ~scoped_lock() noexcept {  _MyMutex.unlock(); }

    scoped_lock(const scoped_lock&) = delete;
    scoped_lock& operator=(const scoped_lock&) = delete;
};

template <>
class scoped_lock<>
{
public:
    explicit scoped_lock() {}
    explicit scoped_lock(adopt_lock_t) {}
    ~scoped_lock() noexcept {}

    scoped_lock(const scoped_lock&) = delete;
    scoped_lock& operator=(const scoped_lock&) = delete;
};
#endif // _HAS_CXX17

(40)函 call_once () , 该函数应该放在线程中使用,确保某个函数,在本进程中,只被调用一次:

#ifndef _M_CEE
#define _WINDOWS_API              __declspec(dllimport) __stdcall
#define _RENAME_WINDOWS_API(_Api) _Api
#endif // _M_CEE

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);
    }
};

// call_once(..) 全局函数,类的静态成员函数,类的可调用对象,都是可以的;
// 但不可以 call_once(...) 类的动态成员函数,因为无法传递对象本身这个参数。
// 在进程全局里生成 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;
    }
}

#undef _WINDOWS_API
#undef _RENAME_WINDOWS_API

(41) condition_variable 条件变量的源码及测试举例

在这里插入图片描述

++ 以及:

在这里插入图片描述

++ 以及:

在这里插入图片描述

++ 以及:

在这里插入图片描述

++ 接着给出 条件变量的源码

// names for wait returns  , cv 含义是 condition_variable 啊
enum class cv_status {  no_timeout,   timeout  }; // 枚举类型
// 本枚举,只是为了区分线程被 nofity 唤醒且拿到锁以后,是没超时醒来,还是发生了超时,仅此而已。

class condition_variable  // class for waiting for conditions
{
private:
    char _Cnd_storage[72]; //这是一个简化定义,参考了内存对齐与数据量需求等方面

    // using _Mtx_t = struct _Mtx_internal_imp_t * ; 对于 mutex 也有类似的定义
    // using _Cnd_t = struct _Cnd_internal_imp_t * ; 缺乏该结构的具体定义,只有其指针
    // get pointer to _Cnd_internal_imp_t inside _Cnd_storage
    _Cnd_t _Mycnd() noexcept { return reinterpret_cast<_Cnd_t>(&_Cnd_storage); }

public:
    using native_handle_type = _Cnd_t; // 这是一个指针类型
    native_handle_type native_handle() { return _Mycnd() ; } // 返回本类的数据成员的地址

    // void __cdecl _Cnd_init_in_situ(_Cnd_t);    // 本类的构造函数,初始化本类的的数据成员
    // int pthread_cond_init ( pthread_cond_t * cond, pthread_condattr_t * attr ) ;
    condition_variable() {      _Cnd_init_in_situ( _Mycnd() );       }

    // void __cdecl _Cnd_destroy_in_situ(_Cnd_t); // 本类的析构函数,析构 本类的数据成员
    // int pthread_cond_destroy ( pthread_cond_t * cond ) ;
    ~condition_variable() noexcept  {   _Cnd_destroy_in_situ(_Mycnd());   }

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

    // 函 _Cnd_signal(...) 总返回 _Thrd_success 。 // wake up one waiter 
    // int pthread_cond_signal ( pthread_cond_t * cond );    
    void notify_one() noexcept {   _Cnd_signal(  _Mycnd()  ) ;  }

    // 函 _Cnd_broadcast(...) 总返回 _Thrd_success 
    // wake up all waiters 将唤醒所有等待锁的线程,这些线程都有机会获取锁,以执行锁后面的代码
    // int pthread_cond_broadcast ( pthread_cond_t * cond ) ;   
    void notify_all() noexcept {   _Cnd_broadcast( _Mycnd() );  }

    // 线程退出时,会进行释放资源、更新状态或通知其他线程。
    // 这些操作常通过线程退出回调、析构函数(如果线程对象有的话)或特定的库函数来实现。
    // register this object for release at thread exit 注册此对象以便在线程退出时释放
    void _Register(unique_lock<mutex>& _Lck, int * _Ready)   
    {   // 在线程结束时,若形参 2 ready 不为 true, 则不再执行条件变量的唤醒操作
        // void __cdecl _Cnd_register_at_thread_exit(_Cnd_t, _Mtx_t, int*);
        _Cnd_register_at_thread_exit(  _Mycnd(), _Lck.release()->_Mymtx(), _Ready  );
    }
    // 这两个函数,服务于 async 、future 系列的线程调用。
    // unregister this object for release at thread exit 注销此对象以便在线程退出时释放
    void _Unregister(mutex& _Mtx) 
    {   // 功能上 _Unregister 似乎是对应于取消 _Register 的操作:不在线程结束时执行唤醒操作了
        // void __cdecl _Cnd_unregister_at_thread_exit(_Mtx_t);
        _Cnd_unregister_at_thread_exit(  _Mtx._Mymtx()  );
    }
/*
template <class _Ty>
class _Associated_state  //本类存储了线程中函数的返回值
{   // ready 初始化为 0 , 0 表还未 ready ,因函数还未执行
    int _Ready;   bool _Ready_at_thread_exit;   condition_variable _Cond;
    
    // 虚析构函数,其子类 _Packaged_state 与 孙类 _Deferred_async_state 都没明确定义的析构函数
    // 可见析构时,若符合线程退出才唤醒的条件,则需要打断 register 的施法,因为函数返回值已经不存在了
    virtual ~_Associated_state() { if (_Has_stored_result && !_Ready)   _Cond._Unregister(_Mtx); }

    virtual void _Do_notify(unique_lock<mutex>* _Lock, bool _At_thread_exit)
    {   // 此是虚函数,但从没有被改写过
        _Has_stored_result = true;

        if (_At_thread_exit)   _Cond._Register(*_Lock, &_Ready); // notify at thread exit
        else                 { _Ready = true;  _Cond.notify_all(); }
    }
};
*/

    // int pthread_cond_wait ( pthread_cond_t * cond , pthread_mutex_t * mutex ) ;
    // 函 _Cnd_wait(...) 总返回 _Thrd_success,故不用检查返回值。本函被下面的重载调用
    void wait(unique_lock<mutex>& _Lck) {  _Cnd_wait( _Mycnd(), _Lck.mutex()->_Mymtx() ); }

    // wait for signal and test predicate
    // wait() 被唤醒后,本线程需再次抢得锁;若断言条件不满足,就继续释放锁,睡眠等待。
    // 若 pred() 返回 F,则线程会释放互斥量,并堵塞在本行;若返 true,则线程继续往下执行。
    template <class _Predicate>  // 第二个参数是函数,例如 lamda 表达式,断言
    void wait(unique_lock<mutex>& _Lck, _Predicate _Pred) { while (!_Pred())  wait(_Lck); }

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

    // wait for signal with timeout  本函是 最基础,是最终被执行的函数!!,被别的成员函数调用
    // 经测试,即使使用了限时等待,若超时后,线程依然没有被 notify() 唤醒,还会继续超时睡眠;
    // 形参2 的时刻必须是相对于 1970 年的时刻,即使用 system_clock,而不能是 steady_clock 。
    // 直到被 notify() 唤醒,且再次拿到了锁。本函的返回值仅仅是提示线程被唤醒时是否发生了超时。
    cv_status wait_until(unique_lock<mutex>& _Lck, const xtime * _Abs_time) // !!
    {
        if (!_Mtx_current_owns(_Lck.mutex()->_Mymtx())) // 看起来是进入等待前要先持有锁
            _Throw_Cpp_error(_OPERATION_NOT_PERMITTED);

//int pthread_cond_timedwait ( pthread_cond_t* cond, pthread_mutex_t* mutex, timespec* abstime );
        const int _Res = _Cnd_timedwait(_Mycnd(), _Lck.mutex()->_Mymtx(), _Abs_time);//此函不会抛出异常

        // enum { _Thrd_success, _Thrd_nomem, _Thrd_timedout, _Thrd_busy, _Thrd_error };
        switch (_Res)
        {
        case _Thrd_success  :    return cv_status::no_timeout;
        case _Thrd_timedout :    return cv_status::timeout;
        default             :    _Throw_C_error(_Res);
        }
    }

    // enum class cv_status  {  no_timeout, timeout }; 
    // wait for duration ,转化为 调用 wait_until(unique_lock<mutex>& _Lck, const xtime* _Abs_time)
    template <class _Rep, class _Period>  // 如果在超时时间以外还没有收到唤醒通知,则线程会停止阻塞。
    cv_status wait_for(unique_lock<mutex>& _Lck, const chrono::duration<_Rep, _Period>& _Rel_time)
    {   
        if ( _Rel_time <= chrono::duration<_Rep, _Period>::zero() ) 
            return cv_status::timeout; // 若形参 2为负值时间,本线程将不再进入睡眠状态,本函直接返回了

        _CSTD xtime _Tgt;  // struct xtime { long long sec ;	long nsec ; };

        // 本函的形参 2 是相对于当前时间的时间间隔,圆整成 10天内,相对于 1970年的绝对时刻,存入形参 1;
        // 若发生了时长截断,形参2 大于 10 天,则返回 true ,否则返回 false。形参一是左值引用。
        // template <class _Rep, class _Period> // int类型最大值 2,147,483,647 约等于 2*10^9 刚好够用
        // bool _To_xtime_10_day_clamped( xtime & _Xt, duration<_Rep, _Period> & _Rel_time )
        const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Rel_time);

        const cv_status _Result = wait_until(_Lck, &_Tgt);  // 调用了上面注释里的成员函数

        if ( _Clamped )   return cv_status::no_timeout; //发生时间截断的线程唤醒,肯定是不会超时的

        return _Result;
    }

    // 这个函数与上面的是一组,都不带断言。没有收到唤醒信号,即使超时也要继续睡眠。
    template <class _Clock, class _Duration>  // wait until time point,有系统时钟与稳定时钟俩种
    cv_status wait_until(unique_lock<mutex>& _Lck, const chrono::time_point<_Clock, _Duration>& _Abs_time)
    {
#if _HAS_CXX20
        static_assert(chrono::is_clock_v<_Clock>, "Clock type required");
#endif // _HAS_CXX20
        for (;;)
        {
            const auto _Now = _Clock::now(); // 若形参 2是相对于当前时间的过去时,直接返回超时;
            if ( _Abs_time <= _Now )   return cv_status::timeout; // 本线程也将不再进入睡眠等待状态

            _CSTD xtime _Tgt; // _T_x_1_d_c(...)函把不同时钟里的时刻都转换为相对于 1970年 的绝对时间
            (void)_To_xtime_10_day_clamped( _Tgt , _Abs_time - _Now);

            const cv_status _Result = wait_until(_Lck, &_Tgt);  // 此行只在被 notify唤醒后才会返回

            if (_Result == cv_status::no_timeout)  return cv_status::no_timeout;//条件变量唤醒
        }
    }

    //*********************以下的函数带断言,以上的函数更简单些

private:
    // 未超时下的断言为假则继续睡眠等待直到断言为真; 超时后的条件唤醒则直接返回断言结果,断言为假也不再睡眠
    template <class _Predicate>   // wait for signal with timeout and check predicate
    bool _Wait_until1(unique_lock<mutex>& _Lck, const xtime* _Abs_time, _Predicate& _Pred)
    {
        while ( !_Pred() )
            if (wait_until(_Lck, _Abs_time) == cv_status::timeout) 
                return _Pred();

        return true;
    }

    // 本函数支持 10 天以上乃至更多天数的断言等待。每 10 天为一个睡眠周期,依次积累。
    template <class _Clock, class _Duration, class _Predicate> // 本函数的语义同上,没有变化
    bool _Wait_until1( unique_lock<mutex>& _Lck,   
        const chrono::time_point<_Clock, _Duration>& _Abs_time, _Predicate& _Pred)
    {
        while ( !_Pred() ) // 先断言一次。先拿到锁以后,再调用 wait_xx 系列的等待函数。
        {
            const auto _Now = _Clock::now(); // 若形参 2是历史时间则直接返回 false,不再睡眠
            if (_Abs_time <= _Now)   return false;

            _CSTD xtime _Tgt;
            const bool _Clamped = _To_xtime_10_day_clamped(_Tgt, _Abs_time - _Now);

            if (wait_until(_Lck, &_Tgt) == cv_status::timeout && !_Clamped) 
                return _Pred();        
        }

        return true;
    }

public:                          // public 以下的成员函数供外界使用
    template <class _Predicate>  // 这个重载函数最简单,未在私有的成员函数的基础上做任何语句增删
    bool wait_until(unique_lock<mutex>& _Lck, const xtime* _Abs_time, _Predicate _Pred)
    {
        return _Wait_until1(_Lck, _Abs_time, _Pred);
    }

    template <class _Clock, class _Duration, class _Predicate>  // 这个重载函数也很简单
    bool wait_until(unique_lock<mutex>& _Lck, const chrono::time_point<_Clock, _Duration>& _Abs_time, _Predicate _Pred)
    {
#if _HAS_CXX20
        static_assert(chrono::is_clock_v<_Clock>, "Clock type required");
#endif // _HAS_CXX20
        return _Wait_until1(_Lck, _Abs_time, _Pred);
    }

    // 函 _To_absolute_time 的返回值类型是 time_point <  steady_clock , duration<long_long,nano>  >
    // auto _To_absolute_time (const chrono::duration<_Rep, _Period>& _Rel_time ) 
    template <class _Rep, class _Period, class _Predicate>
    bool wait_for(unique_lock<mutex>& _Lck, const chrono::duration<_Rep, _Period>& _Rel_time, _Predicate _Pred)
    {   // 等待信号,带有超时限制和断言 wait for signal with timeout and check predicate 
        return _Wait_until1(_Lck, _To_absolute_time(_Rel_time), _Pred);  
    }

};

(42)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值