【C++并发编程实战】2.1 线程的基本管控

本文介绍了C++中线程的基本操作,包括如何发起线程、使用仿函数、lambda表达式作为参数,以及线程的等待、join()方法、异常情况下的处理和detach()分离线程。还提及了thread_guard类用于确保线程安全地执行和清理资源。
摘要由CSDN通过智能技术生成

2.1 线程的基本管控

发起线程

void f(){
    std::cout << "hello, thread\n";
}

std::thread thread1(f);   // 普通函数作为thread构造函数的参数

与C++标准库中的许多类型相同,任何可调用类型(called type)都适用于std::thread

仿函数作为参数
class background_task {
public:
    void operator()()
    {
        std::cout << "background_task\n";
    }
};

std::thread thread1( background_task() );   // 会把这句话当成函数声明
thread1.join();

std::thread thread1{ background_task() };  // 使用c++11的列表初始化
lambda表达式作为参数
std::string hellostr = "hello";
std::thread thread1([](std::string str){
    std::cout << str << '\n';
}, hellostr);

线程等待

一旦启动了线程,就需要明确是要等待它结束(与之汇合),还是任由它独自运行(与之分离)。如果等到std::thread对象销毁时还没决定好,std::thread的析构函数将调用std::terminate终止整个程序。注意,我们只需在std::thread对象销毁前做出决定即可,线程本身可能在汇合或分离前就早已结束。

若需等待线程完成,只需在与之关联的std::thread实例上,通过调用成员函数join()实现。主线程会阻塞在join()处直到等待的线程结束运行。只要调用了join(),隶属于该线程的任何存储空间即会因此清除,std::thread对象遂不再关联到已结束的线程上。事实上,它与任何线程无关联。

join()只能调用一次,只要std::thread对象曾经调用过join(),线程就变得不可再汇合(joinable),成员函数joinable()将返回false

在出现异常的情况下等待

如果线程启动以后有异常抛出,而join()尚未执行,则该join()会被略过。

  • 使用try/catch

    try
    {
        do_something_current_thread();
    }
    catch(...)
    {
        t.join();
        throw;
    }
    t.join();
    
  • RAII手法

    class thread_guard
    {
        std::thread &t;  // thread不能拷贝,用引用管理,如果不加引用,构造的时候一定会进行拷贝构造
    public:
        explicit thread_guard(std::thread &_t): t(_t) { } // 同理,参数也必须加引用避免拷贝
        ~thread_guard()
        {
            if(t.joinable())
                t.join();
        }
        thread_guard(thread_guard const &) = delete;
        thread_guard operator=(thread_guard const &) = delete;
    };
    
    void f()
    {
        std::thread t(myfunc);
    	thread_guard g(t);
    	do_something_in_current_thread();
    }
    

    即便主线程抛出异常,函数f退出,局部对象g会被销毁,其析构函数中会将新线程汇合。

线程detach

调用std::thread对象的成员函数detach(),会令线程在后台运行,遂无法与之直接通信。其归属权和控制权都转移给C++运行时库,一旦线程退出,与之关联的资源都会被正确回收。

调用t.detach()后,std::thread对象不再关联实际的执行线程,即变得不可汇合。

如果要把std::thread对象和线程分离,就必须存在与其关联的执行线程。与join()相同,即只有当t.joinable()返回true时,才能调用t.detach()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值