线程的创建、回收、分离
当一个程序启动后,就会新建一个进程。若此时创建了一个新的==子==线程,原来的进程会==退化成主线程==。
创建线程
构造函数原型
public:
// ① 默认构造函数
thread() noexcept;
// ② 移动构造函数
thread( thread&& other) noexcept;
// ③ 创建线程对象,可以指定任务函数f和参数列表
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args);
private:
// ④ 私有的复制构造函数,说明不想让程序员 copy
thread( const thread&);
获取线程id
原型
std::thread::id get_id() const noexcept
样例
#include <iostream>
#include <thread>
void func(int num, const char *str) {
for (int i = 0; i < 2; ++i) {
std::cout << "子线程t:i = " << i << " num: "
<< num << " str: " << str << std::endl;
}
}
void func1() {
for (int i = 0; i < 3; ++i) {
std::cout << "子线程t1: i = " << i << std::endl;
}
}
int main(int argc, char *argv[]) {
std::cout << "主线程ID:" << std::this_thread::get_id() << std::endl;
std::thread t(func, 123, "hello, world!");
std::thread t1(func1);
std::cout << "线程t的ID: " << t.get_id() << std::endl;
std::cout << "线程t1的ID: " << t1.get_id() << std::endl;
t.join(); // 后面解释为什么join()
t1.join();
return 0;
}
// 由于每个子线程随机抢cpu时间片,输出结果乱七八糟的,每次运行结果都不同。
/*
主线程ID:0x1dbbd6500
线程t的ID: 0x16b6bf000
线程t1的ID: 0x16b74b000
子线程t:i = 子线程t1: i = 0 num: 123 str: hello, world!0
子线程t:i = 1 num: 123 str: hello, world!
子线程t1: i = 1
子线程t1: i = 2
*/
补充
namespace this_thread
在这个命名空间中提供了四个公共的成员函数,以期控制当前的线程。
线程状态:创建态,就绪态,运行态,阻塞态(挂起态),退出态(终止态)- get_id(): 获取id
- sleep_for(params): 休眠一定时间,从运行态变为阻塞态
- sleep_until(params): 休眠直至……
- yield(): 从运行态变为就绪态,然后可以立马抢CPU时间片。
线程回收join
void join();
// 子线程退出时其内核资源由主线程负责回收,若主线程已经退出,
// 相当于房东把房子卖了,子线程(房客)也就不复存在了。
// 所以加入这个阻塞函数,让主线程等待子线程执行完毕(合同结束之后)再回收资源。
线程分离detach
主要是子线程不会再阻塞主线程继续往下执行,但是==当主线程退出了(被抄家了),子线程还是会被销毁(株连九族)==
#include <iostream>
#include <thread>
#include <chrono>
void fun(int, char *; // 定义见上
void func1(); // 定义见上
int main()
{
cout << "主线程的线程ID: " << this_thread::get_id() << endl;
thread t(func, 520, "i love you");
thread t1(func1);
cout << "线程t 的线程ID: " << t.get_id() << endl;
cout << "线程t1的线程ID: " << t1.get_id() << endl;
t.detach();
t1.detach();
// 让主线程休眠, 等待子线程执行完毕
this_thread::sleep_for(chrono::seconds(5));
}
是否可以回收joinable
用于判断主/子线程是否处于关联状态(家长是否还能管得了孩子)
bool joinable() const noexcept;
operator=()
原型
thread& operator=(const thread&) = delete;
thread& operator=(thread&& t) noexcept; // 通过右值,将所有的资源都交给别的线程
样例
#include <iostream>
#include <thread>
#include <chrono>
void fun(int, char *; // 定义见上
void func1(); // 定义见上
// 情况1
int main(int argc, char *argv[]) {
std::cout << "主线程ID:" << std::this_thread::get_id() << std::endl;
std::thread t(func, 123, "hello, world!");
std::thread move_t = std::move(t);
std::thread t1(func1);
std::cout << "线程t的ID: " << move_t.get_id() << std::endl; // ‼️‼️‼️
std::cout << "线程t1的ID: " << t1.get_id() << std::endl;
move_t.join();
t1.join();
return 0;
}
/*
主线程ID:0x1dbbd6500
线程t的ID: 0x16b4c7000
线程t1的ID: 0x16b553000
子线程t:i = 0 num: 123 str: hello, world!
子线程t1: i = 0
子线程t1: i = 1
子线程t1: i = 2
子线程t:i = 1 num: 123 str: hello, world!
*/
// 情况2 将上面的move_t.get_id() 改为 t.get_id()
int main(int argc, char *argv[]) {
std::cout << "主线程ID:" << std::this_thread::get_id() << std::endl;
std::thread t(func, 123, "hello, world!");
std::thread move_t = std::move(t);
std::thread t1(func1);
std::cout << "线程t的ID: " << t.get_id() << std::endl; // 改变这一行‼️‼️‼️
std::cout << "线程t1的ID: " << t1.get_id() << std::endl;
move_t.join();
t1.join();
return 0;
}
/*
主线程ID:0x1dbbd6500
线程t的ID: 0x0
线程t1的ID: 0x16b13b000
子线程t:i = 0 num: 123 str: hello, world!
子线程t:i = 1 num: 123 str: hello, world!
子线程t1: i = 0
子线程t1: i = 1
子线程t1: i = 2
*/
// 线程t的id变成了0x0,说明是一个空指针,因为其所有资源都被交给你move_t
线程id比较
bool operator==(__thread_id __x, __thread_id __y) noexcept
bool operator!=(__thread_id __x, __thread_id __y) noexcept
bool operator< (__thread_id __x, __thread_id __y) noexcept
bool operator<=(__thread_id __x, __thread_id __y) noexcept
bool operator> (__thread_id __x, __thread_id __y) noexcept
bool operator>=(__thread_id __x, __thread_id __y) noexcept