C++thread源码分析

  • thread的内部类;
  • thread的构造函数;
  • 执行流程;
  • 一些对外函数的实现;

引言

如果写一段这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bits/stdc++.h>

struct node {

node() { printf("%p, cons\n", this); }
node(node &n) { printf("%p, copy from %p\n", this, &n); }
node(node &&n) { printf("%p, move from %p\n", this, &n); }
~node() { printf("%p,dest\n", this); }
};

void fun(struct node nd)
{
std::this_thread::sleep_for(std::chrono::seconds(5));
printf("%p\n", &nd);
}

int main()
{
printf("1\n");
std::thread t(fun, node());
printf("2\n");
t.join();
printf("3\n");
return 0;
}

编译命令为:

1
g++ a.cpp -lpthread

输出结果将会类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
1
0x7fff2e724a3f, cons
0x7fff2e7249f8, move from 0x7fff2e724a3f
0x5589443292c8, move from 0x7fff2e7249f8
0x7fff2e7249f8,dest
0x7fff2e724a3f,dest
2
0x7fd6a8499df7, move from 0x5589443292c8
0x7fd6a8499df7
0x7fd6a8499df7,dest
0x5589443292c8,dest
3

可以看出,一开始构造了一个对象位于栈内存0x7fff2e724a3f.

后来他被移动构造到栈内存0x7fff2e7249f8,

再后来他被移动到堆内存0x5589443292c8,

然后按照先构造后析构的顺序,析构了0x7fff2e7249f8, 0x7fff2e724a3f.

线程执行之后,他被移动到栈内存0x7fd6a8499df7,等待五秒并打印了这个地址.

函数执行结束,析构了0x7fd6a8499df7.

在线程结束时,析构了0x5589443292c8.

看完下面文章,你会清楚这些构造,移动和析构,都在什么函数,什么时机中执行.

文件开头定义

1
2
#ifndef _GLIBCXX_THREAD
#define _GLIBCXX_THREAD 1

定义_GLIBCXX_THREAD宏.

1
#pragma GCC system_header

#pragma GCC system_header直到文件结束之间的代码会被编译器视为系统头文件之中的代码。系统头文件中的代码往往不能完全遵循C标准, 所以头文件之中的警告信息往往不显示。(除非用#warning显式指明)。

1
2
3
#if __cplusplus < 201103L
# include <bits/c++0x_warning.h>
#else

__cpluscplus表示当前的c++标准,主要有这几个值

标准
199711L c++98
201103L c++11
201402L c++14
201703L c++17
202002L c++20
202100L c++23(不完整)

显然他们是单调递增的,c++11之前的__cpluscplus都会小于201103L.

这里表示如果当前标准小于c++11,那么不引入下面的代码,而是直接引入<bits/c++0x_warning.h>.

头文件

1
2
3
4
5
6
7
8
#include <chrono>
#include <memory>
#include <tuple>
#include <cerrno>
#include <bits/functexcept.h>
#include <bits/functional_hash.h>
#include <bits/invoke.h>
#include <bits/gthr.h>

作用如下:

头文件 作用
chrono 时间日期相关
memory 内存分配,回收和管理
tuple 元组
cerrno 里面包含了error.h,定义了errno的整数值
bits/functexcept.h 定义了一些内部函数,与抛出异常有关
bits/functional_hash.h 定义了一些哈希相关的类,hash函数最终调用了bits/hash_bytes.h_Hash_bytes
bits/invoke.h 实现了__invoke类,用来调用某个可调用对象
bits/gthr.h 引入了bits/gthr-default.h,这个宏里面定义了thread所需的posix类型
1
#if defined(_GLIBCXX_HAS_GTHREADS)

bits/c++config.h中定义如果gthread库可用,值为1.

可见性

1
2
3
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

命名空间的可见性为默认,实体在共享库中可见,并且可以被抢占.

这个_GLIBCXX_VISIBILITY定义如下:

1
2
3
4
5
6
7
8
9
10
11
#ifndef _GLIBCXX_PSEUDO_VISIBILITY
# define _GLIBCXX_PSEUDO_VISIBILITY(V)
#endif

#if _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY
# define _GLIBCXX_VISIBILITY(V) __attribute__ ((__visibility__ (#V)))
#else
// If this is not supplied by the OS-specific or CPU-specific
// headers included below, it will be defined to an empty default.
# define _GLIBCXX_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY(V)
#endif

如果_GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY,那么设置可见性,不然他就是空的.

如果宏_GLIBCXX_INLINE_VERSION为真,这个_GLIBCXX_BEGIN_NAMESPACE_VERSION将会套上一个版本号为名的命名空间,否则啥也不干.

内部类

_State

1
2
3
4
5
6
7
8
9
10
11
12
/// thread
class thread
{
public:
// Abstract base class for types that wrap arbitrary functors to be
// invoked in the new thread of execution.
struct _State
{
virtual ~_State();
virtual void _M_run() = 0;
};
using _State_ptr = unique_ptr<_State>;

一个抽象基类_State用于封装可执行对象,然后定义一个类型_State_ptr,这是一个用来指向_State的智能指针.

线程id

1
typedef __gthread_t			native_handle_type;

__gthread_tgthr.h中被定义为pthread_t,这是linux的线程id的数据类型,同一进程内唯一.

这个pthread_tpid_t有区别.

pid_t是标志进程的另一套机制.

众所周知,linux的线程是一个特殊的进程,pid_t是这个进程的实际的id.

为了将这些线程伪装成同一个进程,当我们使用getpid()时,这些线程会返回主线程的进程id.

使用gettid()可以获取他们真正的进程id.

这个pid_t是全局唯一的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   class id
{
native_handle_type _M_thread;

public:
id() noexcept : _M_thread() { }

explicit
id(native_handle_type __id) : _M_thread(__id) { }

private:
friend class thread;
friend class hash<thread::id>;

friend bool
operator==(thread::id __x, thread::id __y) noexcept;

friend bool
operator<(thread::id __x, thread::id __y) noexcept;

template<class _CharT, class _Traits>
friend basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id);
};

private:
id _M_id;

这个内部类有一个pthread_t成员,他定义了一些友元函数,以便外部函数使用和比较他的pthread_id.

并且重载了operator<<以便打印线程id.

1
2
3
4
5
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2097. packaged_task constructors should be constrained
// 3039. Unnecessary decay in thread and packaged_task
template<typename _Tp>
using __not_same = __not_<is_same<__remove_cvref_t<_Tp>, thread>>;

__remove_cvref_t可以移除_Tp类型的const,volatitle和引用属性.

然后对比去除这些属性的_Tp类型和thread类型,判断是否相同.

如果相同,那么__not_same类型的value成员会是false,否则为true.

生命周期相关

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  public:
thread() noexcept = default;

template<typename _Callable, typename... _Args,
typename = _Require<__not_same<_Callable>>>
explicit
thread(_Callable&& __f, _Args&&... __args)
{
static_assert( __is_invocable<typename decay<_Callable>::type,
typename decay<_Args>::type...>::value,
"std::thread arguments must be invocable after conversion to rvalues"
);
#ifdef GTHR_ACTIVE_PROXY
// Create a reference to pthread_create, not just the gthr weak symbol.
auto __depend = reinterpret_cast<void(*)()>(&pthread_create);
#else
auto __depend = nullptr;
#endif
_M_start_thread(_S_make_state(
__make_invoker(std::forward<_Callable>(__f),
std::forward<_Args>(__args)...)),
__depend);
}

_Require的实现如下

1
2
3
4
5
6
7
8
9
10
11
template<bool, typename _Tp = void>
struct enable_if
{ };

// Partial specialization for true.
template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };

template<typename... _Cond>
using _Require = typename enable_if<__and_<_Cond...>::value>::type;

_Require的作用:

如果可变模板参数_Cond进行and运算之后的::value为真(也就是这里的_Callable的类型和thread不同),那么_Require类型为合法类型(是一个void).

否则他会是一个错误的类型,编译将会报错.

1
2
3
4
static_assert( __is_invocable<typename decay<_Callable>::type,
typename decay<_Args>::type...>::value,
"std::thread arguments must be invocable after conversion to rvalues"
);

判断_Callable是否可以执行,根据判断结果,__is_invocable最终会继承true_typefalse_type.

对这个__is_invocablevalue,可以得知是否可以调用.

如果不能调用就会报错std::thread arguments must be invocable after conversion to rvalues.

__make_invoker

1
2
3
4
5
6
7
8
9
10
11
#ifdef GTHR_ACTIVE_PROXY
// Create a reference to pthread_create, not just the gthr weak symbol.
auto __depend = reinterpret_cast<void(*)()>(&pthread_create);
#else
auto __depend = nullptr;
#endif
_M_start_thread(_S_make_state(
__make_invoker(std::forward<_Callable>(__f),
std::forward<_Args>(__args)...)),
__depend);
}

__make_invoker会返回一个_Invoker对象,函数的实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
   template<typename... _Tp>
using __decayed_tuple = tuple<typename decay<_Tp>::type...>;

template<typename _Callable, typename... _Args>
static _Invoker<__decayed_tuple<_Callable, _Args...>>
__make_invoker(_Callable&& __callable, _Args&&... __args)
{
return { __decayed_tuple<_Callable, _Args...>{
std::forward<_Callable>(__callable), std::forward<_Args>(__args)...
} };
}
};

__decayed_tuple<typename... _Tp>{__args...}可以将大括号内的元素包装成一个元组,元祖内每个元素的类型由尖括号内的模板参数决定.

return会把这个元祖转换为一个_Invoker,这是一个仿函数.后面会提到.

这里是第一次移动,这个_Invoker位于栈上,构造_Invoker的时候参数被移动到_Invoker的成员_M_t.

_S_make_state

1
2
3
4
5
6
7
   template<typename _Callable>
static _State_ptr
_S_make_state(_Callable&& __f)
{
using _Impl = _State_impl<_Callable>;
return _State_ptr{new _Impl{std::forward<_Callable>(__f)}};
}

这个函数接收一个可执行对象__f把它包装成一个_State_impl对象,并返回指向这个对象的智能指针.

这个_State_impl后面会提到.

这个_State_ptr是前面定义的指向内部类_State的智能指针.

这里是第二次移动,这里把可执行对象_Invoker移动到堆内存,并且用_State_ptr指向他.

这个_State_ptr指向的内存将会在线程结束的时候析构,析构时才会释放堆上的这块空间.

_M_start_thread

1
2
3
4
5
6
7
8
9
10
void
thread::_M_start_thread(_State_ptr state, void (*)())
{
const int err = __gthread_create(&_M_id._M_thread,
&execute_native_thread_routine,
state.get());
if (err)
__throw_system_error(err);
state.release();
}

state指针指向的内容创建一个线程,然后释放state.

创建之后这个线程的线程id会保存在内部对象_M_id_M_thread成员中.

这里state只是release而没有释放内存.

execute_native_thread_routine

execute_native_thread_routine是执行的关键,他被系统调用,并传入上文中state.get()获得的指针

1
2
3
4
5
6
7
static void*
execute_native_thread_routine(void* __p)
{
thread::_State_ptr __t{ static_cast<thread::_State*>(__p) };
__t->_M_run();
return nullptr;
}

一顿转换之后获得了指向可执行对象的智能指针__t.

__t->_M_tun()将会执行_Invokeroperator()().

第三次移动发生在这里.

把堆上的内容移动到栈上,传给std::__invoke,从而执行.

析构函数

1
2
3
4
5
   ~thread()
{
if (joinable())
std::terminate();
}

joinable()会新建一个id,和当前的_M_id对比,如果相同,那么说明这个线程没有传入一个可执行对象,或者已经被join了.

否则执行std::terminate结束进程.详情见这里.

拷贝构造函数和移动构造函数

1
2
3
4
thread(const thread&) = delete;

thread(thread&& __t) noexcept
{ swap(__t); }

拷贝赋值函数和移动赋值函数

1
2
3
4
5
6
7
8
9
10
11
12
13
   thread& operator=(const thread&) = delete;

thread& operator=(thread&& __t) noexcept
{
if (joinable())
std::terminate();
swap(__t);
return *this;
}

void
swap(thread& __t) noexcept
{ std::swap(_M_id, __t._M_id); }

移动赋值之前需要先判断是否terminate,移动__t的内容到当前对象.

基本操作

joinable

1
2
3
bool
joinable() const noexcept
{ return !(_M_id == id()); }

新建一个id,和当前的_M_id对比,如果相同,那么说明这个线程没有传入一个可执行对象,或者已经被join了.

join

1
2
void
join();

实现在thread.cc文件中

1
2
3
4
5
6
7
8
9
10
void
thread::join()
{
int __e = EINVAL;
if (_M_id != id())
__e = __gthread_join(_M_id._M_thread, 0);
if (__e)
__throw_system_error(__e);
_M_id = id();
}

如果当前是joinable的,就调用__gthread_join.

然后_M_id恢复为id().

__gthread_join定义如下:

1
2
3
4
5
6
7
# define __gthrw_(name) __gthrw_ ## name

static inline int
__gthread_join (__gthread_t __threadid, void **__value_ptr)
{
return __gthrw_(pthread_join) (__threadid, __value_ptr);
}

调用__gthrw_pthread_join,传入_M_id._M_thread和一个0.

我目前没有找到他的实现,猜测应该是pthread_join封装,以后找到了再补充.

detach

1
2
void
detach();

他的实现如下

1
2
3
4
5
6
7
8
9
10
void
thread::detach()
{
int __e = EINVAL;
if (_M_id != id())
__e = __gthread_detach(_M_id._M_thread);
if (__e)
__throw_system_error(__e);
_M_id = id();
}

也是和join只能找到这里

1
2
3
4
__gthread_detach (__gthread_t __threadid)
{
return __gthrw_(pthread_detach) (__threadid);
}

获取id

1
2
3
4
5
6
7
8
9
thread::id
get_id() const noexcept
{ return _M_id; }

/** @pre thread is joinable
*/
native_handle_type
native_handle()
{ return _M_id._M_thread; }

返回实现支持的并发线程数量

1
2
3
// Returns a value that hints at the number of hardware thread contexts.
static unsigned int
hardware_concurrency() noexcept;

实现如下

1
2
3
4
5
6
7
8
unsigned int
thread::hardware_concurrency() noexcept
{
int __n = _GLIBCXX_NPROCS;
if (__n < 0)
__n = 0;
return __n;
}

内部类 II

_State_impl

1
2
3
4
5
6
7
8
9
10
11
12
 private:
template<typename _Callable>
struct _State_impl : public _State
{
_Callable _M_func;

_State_impl(_Callable&& __f) : _M_func(std::forward<_Callable>(__f))
{ }

void
_M_run() { _M_func(); }
};

这个类继承了_State并且有一个可执行对象作为成员.

_M_run()实现为执行这个可执行对象.

在构造的位置,他把接收到的接收到的_Invoker,当作_M_func.

一些内部函数

1
2
3
4
5
6
7
8
9
10
   void
_M_start_thread(_State_ptr, void (*)());

template<typename _Callable>
static _State_ptr
_S_make_state(_Callable&& __f)
{
using _Impl = _State_impl<_Callable>;
return _State_ptr{new _Impl{std::forward<_Callable>(__f)}};
}

前面构造函数已经讲过.

内部类 III

_Impl_base

1
2
3
4
5
6
7
8
9
10
#if _GLIBCXX_THREAD_ABI_COMPAT
public:
struct _Impl_base;
typedef shared_ptr<_Impl_base> __shared_base_type;
struct _Impl_base
{
__shared_base_type _M_this_ptr;
virtual ~_Impl_base() = default;
virtual void _M_run() = 0;
};

这个_Impl_base持有一个指向_Impl_base的智能指针.目前意义不明,后面将会提到.

1
2
3
4
5
6
7
  private:
void
_M_start_thread(__shared_base_type, void (*)());

void
_M_start_thread(__shared_base_type);
#endif

实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#if _GLIBCXX_THREAD_ABI_COMPAT
void
thread::_M_start_thread(__shared_base_type __b)
{
if (!__gthread_active_p())
#if __cpp_exceptions
throw system_error(make_error_code(errc::operation_not_permitted),
"Enable multithreading to use std::thread");
#else
__throw_system_error(int(errc::operation_not_permitted));
#endif
_M_start_thread(std::move(__b), nullptr);
}
void
thread::_M_start_thread(__shared_base_type __b, void (*)())
{
auto ptr = __b.get();
// Create a reference cycle that will be broken in the new thread.
ptr->_M_this_ptr = std::move(__b);
int __e = __gthread_create(&_M_id._M_thread,
&execute_native_thread_routine_compat, ptr);
if (__e)
{
ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr.
__throw_system_error(__e);
}
}
#endif

他和前面提到的thread::_M_start_thread(_State_ptr state, void (*)())不同.

目前没看出来哪里会用到这个内部类,日后补充.

_Invoker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 private:
// A call wrapper that does INVOKE(forwarded tuple elements...)
template<typename _Tuple>
struct _Invoker
{
_Tuple _M_t;

template<typename>
struct __result;
template<typename _Fn, typename... _Args>
struct __result<tuple<_Fn, _Args...>>
: __invoke_result<_Fn, _Args...>
{ };

template<size_t... _Ind>
typename __result<_Tuple>::type
_M_invoke(_Index_tuple<_Ind...>)
{ return std::__invoke(std::get<_Ind>(std::move(_M_t))...); }

typename __result<_Tuple>::type
operator()()
{
using _Indices
= typename _Build_index_tuple<tuple_size<_Tuple>::value>::__type;
return _M_invoke(_Indices());
}
};

_M_invoke

这个函数把_M_t中的每个元素取出,传给std::__invoke以执行.

然后返回__result<_Tuple>::type类型的返回值.

这里的具体实现日后补充.

__make_invoker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   template<typename... _Tp>
using __decayed_tuple = tuple<typename decay<_Tp>::type...>;

public:
// Returns a call wrapper that stores
// tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}.
template<typename _Callable, typename... _Args>
static _Invoker<__decayed_tuple<_Callable, _Args...>>
__make_invoker(_Callable&& __callable, _Args&&... __args)
{
return { __decayed_tuple<_Callable, _Args...>{
std::forward<_Callable>(__callable), std::forward<_Args>(__args)...
} };
}
};

上面构造函数处已经介绍.

线程比较操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
inline void
swap(thread& __x, thread& __y) noexcept
{ __x.swap(__y); }

inline bool
operator==(thread::id __x, thread::id __y) noexcept
{
// pthread_equal is undefined if either thread ID is not valid, so we
// can't safely use __gthread_equal on default-constructed values (nor
// the non-zero value returned by this_thread::get_id() for
// single-threaded programs using GNU libc). Assume EqualityComparable.
return __x._M_thread == __y._M_thread;
}

inline bool
operator!=(thread::id __x, thread::id __y) noexcept
{ return !(__x == __y); }

inline bool
operator<(thread::id __x, thread::id __y) noexcept
{
// Pthreads doesn't define any way to do this, so we just have to
// assume native_handle_type is LessThanComparable.
return __x._M_thread < __y._M_thread;
}

inline bool
operator<=(thread::id __x, thread::id __y) noexcept
{ return !(__y < __x); }

inline bool
operator>(thread::id __x, thread::id __y) noexcept
{ return __y < __x; }

inline bool
operator>=(thread::id __x, thread::id __y) noexcept
{ return !(__x < __y); }

纯粹是在数值上对比线程id.

哈希

1
2
3
4
5
6
7
8
9
10
// DR 889.
/// std::hash specialization for thread::id.
template<>
struct hash<thread::id>
: public __hash_base<size_t, thread::id>
{
size_t
operator()(const thread::id& __id) const noexcept
{ return std::_Hash_impl::hash(__id._M_thread); }
};

关键的函数_Hash_impl::hash定义于bits/functional_hash.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct _Hash_impl
{
static size_t
hash(const void* __ptr, size_t __clength,
size_t __seed = static_cast<size_t>(0xc70f6907UL))
{ return _Hash_bytes(__ptr, __clength, __seed); }

template<typename _Tp>
static size_t
hash(const _Tp& __val)
{ return hash(&__val, sizeof(__val)); }

template<typename _Tp>
static size_t
__hash_combine(const _Tp& __val, size_t __hash)
{ return hash(&__val, sizeof(__val), __hash); }
};

他最终调用了_Hash_bytes.定义于hash_bytes.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
_Hash_bytes(const void* ptr, size_t len, size_t seed)
{
static const size_t mul = (((size_t) 0xc6a4a793UL) << 32UL)
+ (size_t) 0x5bd1e995UL;
const char* const buf = static_cast<const char*>(ptr);
// Remove the bytes not divisible by the sizeof(size_t). This
// allows the main loop to process the data as 64-bit integers.
const int len_aligned = len & ~0x7;
const char* const end = buf + len_aligned;
size_t hash = seed ^ (len * mul);
for (const char* p = buf; p != end; p += 8)
{
const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
hash ^= data;
hash *= mul;
}
if ((len & 0x7) != 0)
{
const size_t data = load_bytes(end, len & 0x7);
hash ^= data;
hash *= mul;
}
hash = shift_mix(hash) * mul;
hash = shift_mix(hash);
return hash;
}

打印线程

1
2
3
4
5
6
7
8
9
 template<class _CharT, class _Traits>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __out, thread::id __id)
{
if (__id == thread::id())
return __out << "thread::id of a non-executing thread";
else
return __out << __id._M_thread;
}

this thread

以下是一些获取id,睡眠相关的函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  namespace this_thread
{
/// get_id
inline thread::id
get_id() noexcept
{
#ifdef __GLIBC__
// For the GNU C library pthread_self() is usable without linking to
// libpthread.so but returns 0, so we cannot use it in single-threaded
// programs, because this_thread::get_id() != thread::id{} must be true.
// We know that pthread_t is an integral type in the GNU C library.
if (!__gthread_active_p())
return thread::id(1);
#endif
return thread::id(__gthread_self());
}

/// yield
inline void
yield() noexcept
{
#ifdef _GLIBCXX_USE_SCHED_YIELD
__gthread_yield();
#endif
}

void
__sleep_for(chrono::seconds, chrono::nanoseconds);

/// sleep_for
template<typename _Rep, typename _Period>
inline void
sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
{
if (__rtime <= __rtime.zero())
return;
auto __s = chrono::duration_cast<chrono::seconds>(__rtime);
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__rtime - __s);
#ifdef _GLIBCXX_USE_NANOSLEEP
__gthread_time_t __ts =
{
static_cast<std::time_t>(__s.count()),
static_cast<long>(__ns.count())
};
while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
{ }
#else
__sleep_for(__s, __ns);
#endif
}

/// sleep_until
template<typename _Clock, typename _Duration>
inline void
sleep_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
auto __now = _Clock::now();
if (_Clock::is_steady)
{
if (__now < __atime)
sleep_for(__atime - __now);
return;
}
while (__now < __atime)
{
sleep_for(__atime - __now);
__now = _Clock::now();
}
}
}

C++thread源码分析
https://zzidun.tech/770726c0/
作者
zzidun pavo
发布于
2022年1月31日
许可协议