C++线程对象std::thread之join和detach

C++11 之后有了标准的线程库:std::thread。

Linux环境下,C++的std::thread库底层是对pthread的封装。

一旦一个std::thread绑定了一个函数(如通过有参构造函数构造了一个std::thread对象),则此对象就会立刻开始执行传递进来的函数。

C++ std::thread | 菜鸟教程 (runoob.com)

1. 使用std::thread
  • 包含头文件: #include <thread>
  • 使用CMake编译包含std::thread的文件时,需要显式引入外部依赖包:
find_package(Threads) # 引入外部依赖包
add_executable(ProjectName main.cpp)

target_link_libraries (${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) # 链接Thread库
# 或者下面这种方式
# target_link_libraries (${PROJECT_NAME} pthread)

# 注:使用target_link_libraries链接库时,需要在add_executable之后
1.1 构造函数

ℳ: std::thread::thread - cppreference.com

thread() noexcept;

(1)(since C++11)

thread( thread&& other ) noexcept;

(2)(since C++11)

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

(3)(since C++11)

thread( const thread& ) = delete;

(4)(since C++11)
  • 默认构造函数,创建一个空的 std::thread 执行对象。
  • Move 构造函数,move 构造函数(move 语义是 C++11 新出现的概念,详见附录),调用成功之后 x 不代表任何 std::thread 执行对象。
  • 初始化构造函数,创建一个 std::thread 对象,该 std::thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
  • 拷贝构造函数(被禁用),意味着 std::thread 对象不可拷贝构造。

注意:可被 joinable 的 std::thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.

1.2 构造函数示例
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>

void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread " << n << " executing\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

int main()
{
    int n = 0;
    std::thread t1; // t1 is not a thread
    std::thread t2(f1, n + 1); // pass by value
    std::thread t3(f2, std::ref(n)); // pass by reference
    std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
    t2.join();
    t4.join();
    std::cout << "Final value of n is " << n << '\n';
}
2.  join() 和 detach()
2.1 join()

join: join线程。 调用此函数,主线程需要一直等待子线程执行完毕,才可继续往下执行。

调用join() 函数之后:

  • joinable() == false
2.2 detach()

detach: detach 线程。 将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以在后台单独进行。 意味着主线程不需要等待子线程执行完毕才能往下继续执行(不阻塞主线程)。

一旦线程执行完毕,它所分配的资源将会被释放。

调用 detach 函数之后:

  • *this 不再代表任何的线程执行实例。
  • joinable() == false
  • get_id() == std::thread::id()

另外,如果出错或者 joinable() == false,则会抛出 std::system_error。

2.3 joinable() 与 join()和detach()之间的关系

C++的std::thread类型有一个std::thread::joinable()方法,该方法可以判断一个std::thread对象的状态是否为joinable。

当调用detach() 或join() 方法时,thread对象的状态将由 joinable转为 non-joinable,也就是std::thread::joinable()的返回值会由true变为false。

【C++】join()和detach|不join()也不detach()的后果一、join()和detach()_共享变量
图1. joinable()的状态转换
 2.4 thread对象不调用join()也不调用detach()会发生什么?

首先来看一下 std::thread的析构函数内容:

    ~thread()
    {
      if (joinable())
	    std::terminate();
    }

可以看出如果一个std::thread对象在析构时,其joinable()状态为 true,则会直接调用std::terminate() 去中断程序。

根据图1可知,通过有参构造函数创建了一个 std::thread对象之后,其状态时 joinable() == true的,只有当 调用 .join() 或者 . detach之后, joinable() == false。

所以如果 thread对象创建之后,绑定了执行函数,既不调用join()  也不调用 detac(),则在其对象释放之时,系统会直接 中断⛔️(std::terminate)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值