Thread只是一个类,Thread对象可以与实际运行的线程产生联系,利用thread对象对线程进行操作,但是实际线程的存亡与thread对象的存亡并无绝对的决定关系。
1. 构造函数
1、默认构造函数
thread() noexept;//空的thread对象
2、初始化构造函数
template<class Fn,class…Args>
explicit thread(Fn && fn,Args && … args)
创建thread对象,并将会执行fn代表的函数,fn为可调用对象 ,其参数由args给出,依据变长模板的实例化标准。
3、移动构造函数
thread(thread&& x) noexcept;
x所代表的线程的任务被交由当前thread对象,x不再与之前关联的线程有关。
2. 其他成员函数
(1)get_id
获取当前进程ID,通过thread对象获得关联线程的ID,线程ID都是唯一标识的,因此可以通过thread对象调用get_id()来区分,但是thread对象间可以转交线程,因此move操作、detach操作后,get_id()来区分的方法变得不可靠。thread对象与线程脱钩后,通过其调用get_id()会返回当前线程的ID。
(2) joinable
bool joinable() const noexcept
{ return !(_M_id == id()); }
检查当前进程是否可以被join,由默认构造函数生成的thread不可被join,该对象调用joinable返回false,而如果一个线程被创建但是仍未join,那么该对象调用joinable会返回true。只有当thread对象与线程关联时,通过thread对象调用joinable可以返回true,断开关联后、thread对象转交后,调用joinable都会返回false。
(3) join
阻塞式简单执行线程,通过thread对象调用join,使得当前线程等待对象线程执行完毕返回,并使thread对象与线程断开,因此一个thread对象只能调用一次,除非它被move赋值。
(4)detach
非阻塞式执行线程,通过thread对象调用detach,使得当前线程继续执行,thread对象创建的线程转入后台运行,并使thread对象与线程断开,一个thread对象只能调用一次,除非它被move赋值过。
【例1】
#include <iostream>
#include <thread>
#include <chrono>
void func1(int a,int b){std::cout << a + b << std::endl;}
void func2(){std::cout << "Func 2\n";}
int main()
{
std::thread t1(func1, 1, 2);//变长模板模式,函数指针调用
std::thread t2(func2);
if (t1.joinable())
std::cout << "Thread t1 is joinable\n";
else
std::cout << "Thread t1 is not joinable\n";
if (t2.joinable())
std::cout << "Thread t2 is joinable\n";
else
std::cout << "Thread t2 is not joinable\n";
std::cout << "T1's ID is :\t" << t1.get_id() << std::endl
<< "T2's ID is :\t" << t2.get_id() << std::endl;
t1.join();
t2.detach();
return 0;
}
输出结果:
Thread t1 is joinable
Thread t2 is joinable
T1's ID is : 2724
T2's ID is : 12652
3
Func 2
(5)std::swap
交换量thread对象挂钩线程的底层句柄,可理解为交换了线程实体(存疑)。std::swap(Thread1,Thread2),Thread1.swap(Thread2)均可用。
【例2】
#include <iostream>
#include <thread>
#include <chrono>
void func1(int a,int b)
{
std::cout << a + b << std::endl;
}
void func2()
{
std::cout << "Func 2\n";
}
int main()
{
std::thread t1(func1, 1, 2);
std::thread t2(func2);
std::thread t3(func1, 2, 3);
std::thread t4(func2);
if (t1.joinable() && t2.joinable())
{
t1.join();
t2.join();
}
std::cout << "Swap t1 and t2 after join\n";
std::swap(t1, t2);
std::cout <<"t1's id:"<< t1.get_id() << std::endl;
std::cout <<"t2's id:"<< t2.get_id() << std::endl;
// t1与t2的id均为0,即当前线程(主线程)id,因为它们都join过了,thread对象与线程脱钩.
std::swap(t3, t4);//所以只能在thread对象与线程脱钩之前swap
std::cout << "\nt3 after swap:\n";
t3.join();
std::cout << "\nt4 after swap:\n";
t4.join();
return 0;
}
(6)native_handle
返回thread对象挂钩线程的本地句柄。
(7)hardware_concurrency
【static】
检测硬件并发特性,返回当前平台可支持的最大线程并发数目,仅供参考的系统提示(hint)。
3. this_thread
std::this_thread是thread类内一个命名空间
(1)this_thread::get_id
获取当前进程ID
namespace this_thread
{
_NODISCARD thread::id get_id() noexcept;
}
(2)this_thread::sleep_for
使当前线程休眠一段时间(_Rel_time):不过往往休眠的时间会超过这个数值,可以通过更高精度的计时器验证。
template< class Rep, class Period >
void sleep_for( const std::chrono ::duration<Rep,Period>& sleep_duration );
(3)this_thread::sleep_until
使当前线程休眠到某个时间点(_Abs_time)。
template< class Clock, class Duration >
void sleep_until( const std::chrono::time_point
<Clock,Duration>& sleep_time );
(4)this_thread::yield
放弃当前线程的执行,让出自己的时间片给其他线程使用,特定适用于CPU非常忙碌的时候,否则建议使用sleep_for()与sleep_until(),以便于其他目的。