线程创建回收分离

 

线程的创建、回收、分离

当一个程序启动后,就会新建一个进程。若此时创建了一个新的==子==线程,原来的进程会==退化成主线程==。

创建线程

构造函数原型

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

在这个命名空间中提供了四个公共的成员函数,以期控制当前的线程。

线程状态:创建态,就绪态,运行态,阻塞态(挂起态),退出态(终止态)
  1. get_id(): 获取id
  2. sleep_for(params): 休眠一定时间,从运行态变为阻塞态
  3. sleep_until(params): 休眠直至……
  4. 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

参考资料

  1. linux教程by爱编程的大丙