(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)
谢谢