部分前置知识
- 命名空间:
this_thread
,里面有:thread::id get_id()
:获取当前线程idinline void yield()
:线程让出CPU时间片,但是当前线程,没有阻塞,依旧是就绪状态,等待cpu下次调度inline void sleep_until(const xtime* _Abs time)
:线程休眠到某一个时刻void sleep_for(const chrono::duration<_Rep,_Period>& _Rel_time
:配合命名空间chrono
进行睡眠,睡眠指定的时间片
chrono
,和时间有关的命名空间,里面有各种时间单位函数:- 比如
senconds
, 使用:chrono::seconds(2);
2秒
- 比如
- C++11主线程和子线程关系:
- 如果子线程不是
detach
,则主线程必须join
等待子线程运行完成,不让程序会中断报错 - 如果子线程设置为
detach
,主线程就不需要等待子线程运行完成,但是主线程结束,子线程也会被迫结束 - linux相对没有那么严格,主线程不一定要join等待子线程结束,但是主线程结束,子线程也就结束了
- 如果子线程不是
- 线程的本质:
- 线程的本质是一个线程栈,一个线程一个线程栈,需要绑定一个对应的入口函数
C++11多线程
-
C++11线程函数的用法
#include<thread> //using namespace std; void threadFunc(int time) { //让子线程睡眠time秒 std::this_thread::sleep_for(std::chrono::seconds(time)); std::cout << "hello thread1!" << std::endl; } int main() { std::thread t(threadFunc,2); t.join(); //没有设置detach,必须join等待 cout<<"main thread down!"<<endl; return 0; } /* 运行结果 hello thread1! main thread down ! */
-
线程对象
thread
相关成员函数- 构造函数
-
默认构造函数:创建一个空的thread对象
thread() noexcept: _Thr{} {} ; // 补充 _Thrd_t _Thr; //成员变量 // 成员变量结构体的定义 using _Thrd_id_t = unsigned int; struct _Thrd_t { // thread identifier for Win32 void* _Hnd; // Win32 HANDLE _Thrd_id_t _Id; };
-
初始化构造函数:创建一个thread对象,这个对象可以被joinable,新产生的线程对象会调用线程函数,函数的参数也就是传入的参数
template <class _Fn, class... _Args, enable_if_t<!is_same_v<_Remove_cvref_t<_Fn>, thread>, int> = 0> _NODISCARD_CTOR_THREAD explicit thread(_Fn&& _Fx, _Args&&... _Ax) { _Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...); }
-
拷贝构造、赋值重载都是delete,提供右值拷贝构造,右值赋值重载
-
get_id()
:返回的是一个对象std::thread::id
,同this_thread::get_id();
-
joinable()
:检测当前线程是否可以被join -
join()
: join等待线程 -
detach()
: detach线程,将线程和主线程分离
-
- 构造函数
-
TIP:
- 默认构造的线程对象,是没有线程入口函数的,
joinable()
是false,如果对不能join的线程join是触发std::terminate()
中止; std::thread
对象再线程函数运行期间必须有效,如果对象销毁了,函数还在运行,程序会崩溃,而detach方法可以让线程对象和线程函数分离;
- 默认构造的线程对象,是没有线程入口函数的,