码迷,mamicode.com
首页 > 其他好文 > 详细

[原]std::thread总结

时间:2018-08-11 13:52:59      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:play   拷贝   _id   color   microsoft   fir   join()   cpp   tor   

缘起

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

std::thread

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

类定义

  1. class thread 
  2. { 
  3. public: 
  4. thread() noexcept; 
  5. thread( thread&& other ) noexcept; 
  6. template< class Function, class... Args > 
  7. explicit thread( Function&& f, Args&&... args ); 
  8. thread(const thread&) = delete; 
  9. ~thread(); 
  10. thread& operator=( thread&& other ) noexcept; 
  11. bool joinable() const noexcept; 
  12. std::thread::id get_id() const noexcept; 
  13. native_handle_type native_handle(); 
  14. void join(); 
  15. void detach(); 
  16. void swap( thread& other ) noexcept; 
  17. static unsigned int hardware_concurrency() noexcept; 
  18. }; 

从定义中我们可以得知:

各个成员函数的简单介绍

例子

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

  • 支持移动语义,但不支持拷贝语义
  1. #include <thread> 
  2. void some_function() {} 
  3. void some_other_function() {} 
  4. int main() 
  5. { 
  6. std::thread t1(some_function); // 构造一个thread对象t1 
  7. std::thread t2 = std::move(t1); // 把t1 move给另外一个thread对象t2,t1不再管理之前的线程了。 
  8. // 这句不需要std::move(),从临时变量进行移动是自动和隐式的。调用的是operator=(std::thread&&) 
  9. t1 = std::thread(some_other_function); 
  10. std::thread t3; 
  11. t3 = std::move(t2); // 把t2 move给t3 
  12. // 把t3 move给t1,非法。因为`t1`已经有了一个相关的线程,会调用`std::terminate()`来终止程序。 
  13. t1 = std::move(t3); 
  14. } 
  • 通过调用join()成员函数来等待线程结束
  1. #include <iostream> 
  2. #include <thread> 
  3. #include <chrono> 
  4.  
  5. void foo() { 
  6. std::this_thread::sleep_for(std::chrono::seconds(1)); 
  7. } 
  8.  
  9. int main() { 
  10. std::cout << "starting first helper...\n"; 
  11. std::thread helper1(foo); 
  12. helper1.join(); 
  13. } 
  • 传递参数给线程函数
  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. { 
  4. char buffer[1024]; 
  5. sprintf(buffer, "%i", some_param); 
  6. std::thread t(f, 3, buffer); 
  7. t.detach(); 
  8. } 

局部变量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. { 
  5. public: 
  6. void run0(){} 
  7. void run1(int a) {} 
  8. void run2(int a, int b) {} 
  9. int run3(int a, char b, const std::string& c) {return 0;} 
  10. int run4(int& a, double b, float c, char d) { ++a; return 0; } 
  11. static void run_static(int a) {} 
  12. }; 
  13.  
  14. int main() 
  15. { 
  16. CRunner runner; 
  17. int a = 0; 
  18. // 使用std::mem_fun 
  19. std::thread t0(std::mem_fun(&CRunner::run0), &runner); 
  20. // 使用std::mem_fun_ref,注意与std::mem_fun的区别 
  21. std::thread t1(std::mem_fun_ref(&CRunner::run1), std::ref(runner), 1); 
  22. // 使用std::mem_fn,std::mem_fn支持多于一个参数的函数,std::mem_fun不支持。 
  23. std::thread t2(std::mem_fn(&CRunner::run2), std::ref(runner), 1, 2); 
  24. // 使用std::bind + std::mem_fn 
  25. std::thread t3(std::bind(std::mem_fn(&CRunner::run3), &runner, 1, 2, "data"));  
  26. // 使用std::mem_fn,注意std::ref的用法,如果不用std::ref行不行? 
  27. std::thread t4(std::mem_fn(&CRunner::run4), &runner, std::ref(a), 2.2, 3.3f, ‘d‘);  
  28. // 使用类的静态函数 
  29. std::thread t5(&CRunner::run_static, 1); 
  30.  
  31. t0.join(); 
  32. t1.join(); 
  33. t2.join(); 
  34. t3.join(); 
  35. t4.join(); 
  36. t5.join(); 
  37. } 

参考资料

[原]std::thread总结

标签:play   拷贝   _id   color   microsoft   fir   join()   cpp   tor   

原文地址:https://www.cnblogs.com/bianchengnan/p/9459490.html

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!