2024.3.27记——C++多线程系列文章(一)

启动线程

每个c++程序都至少有一个线程,即运行main()函数的线程,它由c++运行时系统启动。随后可以在此线程上发起更多线程来构成多线程程序,其他线程以别的函数作为入口。c++借std::thread对象管控线程。最简单的任务就是运行一个普通函数,返回空,也不接收参数。函数在自己的线程上运行,等它一返回,线程即随之终止。复杂任务则是另一个极端,它可以由函数对象(function object)表示,还接收参数,并且在运行过程中,经由某种消息系统协调,按照指定执行一系列独立操作,只有收到某指示信号(依然经由消息系统接收)时,线程才会停止。不论线程具体要做什么,也不论它从程序内哪个地方发起,只要通过C++标准库启动线程,归根结底,代码总会构造std::thread对象:

void do_some_work();
std::thread my_thread(do_some_work);

当然,我们需要包含头文件,才能让编译器清楚std::thread类的定义。

与 C++标准库中的许多类型相同,任何可调用类型都适用于std::thread。下面表示可调用类(重载调用操作符的类):

class background_task
{
public:
    void operator()() const
    {
        do_something();
        do_something_else();
    }
};
background_task f;
std::thread my_thread(f);

也可以使用lambda函数:

std::thread my_thread([]{
    do_something();
    do_something_else();
});

一旦启动了线程,我们就需明确是要等待它结束,还是任由它独自运行。假如等到std::thread对象销毁之际还没决定好,那std::thread的析构函数将调用std::terminate()终止整个程序。

请注意,我们只需在std::thread 对象销毁前做出决定——线程本身可能在汇合或分离前就早已结束。如果选择了分离,且分离时新线程还未结束运行,那它将继续运行,甚至在std::thread对象销毁很久之后依然运行,它只有最终从线程函数返回时才会结束运行。

等待线程结束

若需等待线程完成,那么可以在与之关联的std::thread实例上,通过调用成员函数join()实现。

join()简单而粗暴,我们抑或一直等待线程结束,抑或干脆完全不等待。如需选取更精细的粒度控制线程等待,如查验线程结束与否,或限定只等待一段时间,那我们便得改用其他方式,如条件变量和future(后续介绍)

只要调用了join(),隶属于该线程的任何存储空间即会因此清除,std::thread对象遂不再关联到已结束的线程。对于某个给定的线程,join()仅能调用一次;只要std::thread对象曾经调用过join(),线程就不再可汇合(joinable),成员函数joinable()将返回false。

在后台运行线程

调用std::thread对象的成员函数detach(),会令线程在后台运行,遂无法与之直接通信。假若线程被分离,就无法等待它完结,也不可能获得与它关联的std::thread对象,因而无法汇合该线程。然而分离的线程确实仍在后台运行,其归属权和控制权都转移给C++运行时库(runtime library,又名运行库),由此保证,一旦线程退出,与之关联的资源都会被正确回收。

一个简单的例子

std::this_thread::get_id() 这个函数可以打印线程ID,每个线程有唯一的ID,在测试过程中可以查看是否真正启动了多线程。

#include <iostream>
#include <thread>
void print() {
  std::cout << "This is a joined ID:" << std::this_thread::get_id()
            << std::endl;
}
void do_something() {
  for (int i = 0; i < 10; ++i) {
    std::cout << "This thread is detached ID:" << std::this_thread::get_id()
              << std::endl;
  }
}
int main() {
  std::thread t1(print);
  std::thread t2(do_something);
  if (t1.joinable()) {
    t1.join();  // main线程等待t1线程结束
  }
  if (t2.joinable()) {
    t2.detach();  //  main线程与t2线程分离,不再等待线程
  }
  std::cout << "Main end ID:" << std::this_thread::get_id() << std::endl;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值