c++线程管控

线程管控

发起线程

启动线程

c++标准库启动线程需要构造std::thread对象,任何可调用对象都可以适用

// 函数调用
void doSomeWork();
std::thread mythread(doSomeWork);

// 有函数调用操作符的类
class background_task
{
    public:
        void operator() () const
        {
            doSomeThing();
            doSomeThingElse();
        }
};
background_task t;
std::thread my_thread(t);

// lambda表达式
std::thread my_thread([]{
    doSomeThing();
    doSomeThingElse();
});

启动后主线程处理

在线程结束前,我们需要保证线程中访问到的外部数据始终有效,所以通常我们要把需要的数据复制到线程内部,而不是共享。特别注意线程不要共享启动线程函数中的局部变量,除非可以保证线程在函数退出前结束


struct my_func
{
    int& i_;
    my_func(int& i) :i_(i) {}
    void operator()()
    {
        do_something(i);    // 这里i可能是销毁的指针
    }
}

void oops()
{
    int some_local_state =0;
    std::thread t(my_func, some_local_state);
    t.detach();
}

等待线程完成

  • 上述问题的一种解决办法是,调用join
  • join会阻塞主线程等待创建的线程汇合,只能调用一次,调用后joinable()将返回false
  • 调用join前要注意主线程是否会因为异常抛出,对于异常处理也要调用join(),可以使用RAII的方法,使用guard处理
    std::thread t(my_func);
    t.join();

在后台运行线程

  • 与join对应,调用detach()可以让线程在后台运行,分离后线程的运行权利控制权都交给了运行时库处理
  • 对std::thread对象调用detach()后,对象不在关联线程,也不可以再汇合

对线程函数传参

  • 向线程的函数或者可调用对象传参时,直接在std::thread的构造函数中添加更多参数即可
  • 线程内部有存储空间,参数会按照默认方式复制到这里,然后副本会被当做临时变量,用右值的方式传给新线程上的函数或调用对象。如果参数需要类型转化,转化是在新线程开始时进行,std::thread中拷贝参数是在原线程中拷贝,复制的内容也是std::tread构造函数中原本的内容。
class MyClass
{
    ....
};

void func(MyClass& c)
{
    ...
};

int main()
{
    MyClass c;
    std::thread t(func, c);
    t.join();
    return 0;
}
  • 案例无法通过编译,因为在std::thread,在构造时会原本的复制MyClass类型到线程的存储空间中,当做move_only类型,并以右值的形式传递。最终func收到的是一个右值作为参数,而func希望的是一个非const参数,所以编译失败。解决的办法可以是func改为接受一个const MyClass& 引用,或者用std::ref包装参数.
std::thread t(func, std::ref(c));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值