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

来源:互联网 发布:淘宝主图多少尺寸 编辑:程序博客网 时间:2024/06/17 11:51

启动一个线程

#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;}

即可完美运行。

原创粉丝点击