原 总结 C++11 thread 

概览

从C++11开始提供了线程的支持,终于可以方便的编写跨平台的线程代码了。除了std::thread类,还提供了许多其它便利同步的机制,本篇总结是C++11学习笔记系列的首篇总结。

std::thread

std::thread定义在<thread>中,提供了方便的创建线程的功能。

类定义

  1. class thread 



  2. public: 

  3. thread() noexcept; 

  4. thread( thread&& other ) noexcept; 

  5. template< class Function, class... Args > 

  6. explicit thread( Function&& f, Args&&... args ); 

  7. thread(const thread&) = delete; 

  8. ~thread(); 

  9. thread& operator=( thread&& other ) noexcept; 

  10. bool joinable() const noexcept; 

  11. std::thread::id get_id() const noexcept; 

  12. native_handle_type native_handle(); 

  13. void join(); 

  14. void detach(); 

  15. void swap( thread& other ) noexcept; 

  16. static unsigned int hardware_concurrency() noexcept; 

  17. }; 

从定义中我们可以得知:

各个成员函数的简单介绍

例子

因为thread类比较简单,我们通过几个例子来学习。

  • 支持移动语义,但不支持拷贝语义
  1. #include <thread> 

  2. void some_function() {} 

  3. void some_other_function() {} 

  4. int main() 



  5. std::thread t1(some_function); // 构造一个thread对象t1 

  6. std::thread t2 = std::move(t1); // 把t1 move给另外一个thread对象t2,t1不再管理之前的线程了。 

  7. // 这句不需要std::move(),从临时变量进行移动是自动和隐式的。调用的是operator=(std::thread&&) 

  8. t1 = std::thread(some_other_function); 

  9. std::thread t3; 

  10. t3 = std::move(t2); // 把t2 move给t3 

  11. // 把t3 move给t1,非法。因为`t1`已经有了一个相关的线程,会调用`std::terminate()`来终止程序。 

  12. t1 = std::move(t3); 



  • 通过调用join()成员函数来等待线程结束
  1. #include <iostream> 

  2. #include <thread> 

  3. #include <chrono> 


  4. void foo()  



  5. std::this_thread::sleep_for(std::chrono::seconds(1)); 




  6. int main() 



  7. std::cout << "starting first helper...\n"; 

  8. std::thread helper1(foo); 

  9. helper1.join(); 



  • 传递参数给线程函数
  1. void f(int i, std::string const& s); 

  2. std::thread t(f, 3 "hello"); 

注意:参数会以默认的方式被复制到内部存储空间,直到使用的时候才会转成对应的类型。

下面的例子有问题吗?有什么问题?

  1. void f(int i, std::string const& s); 

  2. void oops(int some_param) 



  3. char buffer[1024]; 

  4. sprintf(buffer, "%i", some_param); 

  5. std::thread t(f, 3, buffer); 

  6. t.detach(); 



局部变量buffer的指针会被传递给新线程,如果oops()buffer被转换成string之前退出,那么会导致未定义的行为。解决之道是在构造std::thread的时候传递string变量。std::thread t(f, 3, std::string(buffer));

可以使用std::ref()来显示表明要传递引用,就像std::bind()那样。

  1. std::thread t(update_data_for_widget, w, std::ref(data)); 

  • 使用类的成员函数作为线程参数
  1. #include <thread> 

  2. #include <string> 

  3. class CRunner 



  4. public: 

  5. void run0(){} 

  6. void run1(int a) {} 

  7. void run2(int a, int b) const {} 

  8. int run3(int a, char b, const std::string& c) {return 0;} 

  9. int run4(int& a, double b, float c, char d) { ++a; return 0; } 

  10. static void run_static(int a) {} 

  11. }; 


  12. int main() 



  13. CRunner runner; 

  14. int a = 0; 

  15. // 使用std::mem_fun,需要传指针 

  16. std::thread t0(std::mem_fun(&CRunner::run0), &runner); 

  17. // 使用std::mem_fun_ref,可以传引用或副本 

  18. std::thread t1(std::mem_fun_ref(&CRunner::run1), std::ref(runner), 1); 

  19. // std::thread t1(std::mem_fun_ref(&CRunner::run1), runner, 1); 


  20. // 使用std::mem_fn,std::mem_fn支持多于一个参数的函数,std::mem_fun不支持。 

  21. std::thread t2(std::mem_fn(&CRunner::run2), std::ref(runner), 1, 2); 

  22. // 使用std::bind + std::mem_fn 

  23. std::thread t3(std::bind(std::mem_fn(&CRunner::run3), &runner, 1, 2, "data"));  

  24. // 使用std::mem_fn,注意std::ref的用法,如果不用std::ref行不行? 

  25. std::thread t4(std::mem_fn(&CRunner::run4), &runner, std::ref(a), 2.2, 3.3f, 'd');  

  26. // 使用类的静态函数 

  27. std::thread t5(&CRunner::run_static, 1); 


  28. t0.join(); 

  29. t1.join(); 

  30. t2.join(); 

  31. t3.join(); 

  32. t4.join(); 

  33. t5.join(); 



注:

更多

虽然在之前的例子中的函数有返回值,但是我们却不能获得,想获得返回值我们需要使用std::future,关于std::future的总结,后续会慢慢补充,敬请期待。

参考资料

最新文章

  1. AJAX 同步异步笔记
  2. 网络电视精灵~分析~~~~~~简单工厂模式,继承和多态,解析XML文档,视频项目
  3. 通过Oracle补充日志,找到锁阻塞源头的SQL
  4. 10 Common Problems Causing Group Policy To Not Apply
  5. CentOS mysql硬盘满了挂载阿里云硬盘
  6. Java URLClassLoader和ClassLoader
  7. 31.DDR2问题3_waring?
  8. 【今日推荐】10大流行的 Metro UI 风格的 Bootstrap 主题和模板
  9. xlslib库使用简记
  10. imageview设置图片时超长超大图片超出限制(OpenGLRenderer: Bitmap too large to be uploaded into a texture (996x9116, max=4096x4096))
  11. powerdesigner 不能自动生成注释的解决方法(三步解决)
  12. 第八周 ip通信基础回顾
  13. liunx本地网卡流量监控
  14. Kafka中bootstrap-server、broker-list和zookeeper的区别
  15. How to solve “Dynamic Web Module 3.1 requires Java 1.7 or newer” in Eclipse
  16. IE8以下兼容
  17. postgresql总结
  18. vsftp
  19. 【CobaltStrike】CobaltStrike简介与使用
  20. winform datagridview 不显示默认第一列 不显示未绑定列 数据源发生改变时自动更新 (转)

热门文章

  1. Eclipse字体及背景色设置和工作空间字符编码设置
  2. JS下拉框联动
  3. Floyd--P1119 灾后重建
  4. SPOJ FISHER + FPOLICE SPFA+背包
  5. css代码实现列表等宽
  6. linux下启动mysql提示:Timeout error occurred trying to start MySQL Daemon
  7. 渗透测试 - HPP数据污染 - 原理 | 场景
  8. Mybatis 持久化,持久层
  9. POJ 1836:Alignment
  10. C++ 一般模板友元关系