C++11并发编程-01(线程的启动、传参)

启动一个线程

#include <iostream>
#include <thread>

int main()
{
    std::cout << "thread starting..." << std::endl;
    std::thread myThread([]{
       std::cout<<"this is a new thread!"<< std::endl;
    });
    myThread.join();
    return 0;
}

运行结果:

thread starting…
this is a new thread!


要点:

  1. std::thread的构造可传入一切callable对象,如: 普通函数、lambda、函数指针、bind对象、拥有()符号重载的函数对象。
  2. 你一定要确保在std::thread对象被销毁前(而不是线程结束前)显式地调用std::thread对象的 join 或 detach方法。
  3. std::thread对象被销毁并不代表线程一定结束了。特别是当你调用了detach之后,当该thread对象被销毁,线程很可能还在运行中。
  4. 如果你调用detach分离线程,那么应当确保线程所需要访问的数据是有效的。 特别注意局部变量。
  5. join的作用是当前线程等待其对应的子线程结束之后才会结束,可以有效防止子线程对局部变量的依赖风险。detach的作用是将指定的子线程从当前线程中分离,当前线程不再等待该线程执行完毕才结束,同时相当于是放弃了对该线程的控制权,再也无法获得该线程的对象并对其进行通讯或控制。
  6. join 会阻塞主(父)线程的执行,考虑以下代码:
#include <iostream>
#include <thread>
#include <chrono>
int main()
{
    std::thread thread1([]{
       std::cout<<"thread1 started"<< std::endl;
       std::this_thread::sleep_for(std::chrono::seconds(3));
       std::cout<<"thread1 end!" << std::endl;
    });

    thread1.join();

    std::thread thread2([]{
       std::cout<<"thread2 started"<< std::endl;
       std::this_thread::sleep_for(std::chrono::seconds(3));
       std::cout<<"thread2 end!" << std::endl;
    });

     thread2.join();

    std::cout<<"after join";
    //myThread.detach();
    return 0;
}

当main输出after join时,实际上等待了6秒,即 thread1.join() 阻塞主线程等待thread1执行完成后才开始向下执行。

#include <iostream>
#include <thread>
#include <chrono>
int main()
{
    std::thread thread1([]{
       std::cout<<"thread1 started"<< std::endl;
       std::this_thread::sleep_for(std::chrono::seconds(3));
       std::cout<<"thread1 end!" << std::endl;
    });



    std::thread thread2([]{
       std::cout<<"thread2 started"<< std::endl;
       std::this_thread::sleep_for(std::chrono::seconds(3));
       std::cout<<"thread2 end!" << std::endl;
    });

    thread1.join();
    thread2.join();

    std::cout<<"after join";
    //myThread.detach();
    return 0;
}

把thread1.join()放到thread2.join()之前则 main输出after join时总共只等待了3秒。以上例子同时还说明了std::thread的执行实际上在thread对象构造的时候就已经开始,而不是等到join或者detach被调用才开始(但并不保证构造语句执行后线程就一定成功跑起来了,有可能会延时)。

给新线程传递参数
实际上就是给thread对象绑定的函数传递参数:

#include <iostream>
#include <thread>
#include <chrono>
#include <functional>
#include <mutex>
std::mutex g_mutex;
int main()
{
    auto func = [](int id){
        g_mutex.lock();
        std::cout<<"thread"<< id <<" started"<< std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(3));
        std::cout<<"thread"<< id <<" end!" << std::endl;
        g_mutex.unlock();
     };
    std::thread thread1(func,1);
    std::thread thread2(func,2);

    thread1.join();
    thread2.join();

    std::cout<<"after join";
    //myThread.detach();
    return 0;
}

运行结果:
thread1 started
thread1 end!
thread2 started
thread2 end!
after join

给线程传递引用
以下代码编译会报错:

#include <iostream>
#include <thread>

using namespace std;

foo(int& val){
    val = 123;
}

int main()
{
    int num = 0;
    thread (foo,num).join();
    return 0;
}

原因是c++默认会把线程实参进行拷贝,即在子线程中访问到的引用实际上已经是副本的引用,依然改变不了原变量,所以这是没有意义的。笔者目前的编译器版本(gcc version 4.9.2)会对以上代码报错。
解决方案是 对实参加上 std::ref();

#include <iostream>
#include <thread>

using namespace std;

foo(int& val){
    val = 123;
}

int main()
{
    int num = 0;
    thread (foo,ref(num)).join();
    return 0;
}

即可完美运行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值