当前位置:   article > 正文

C++ 进程与线程---std::thread()_std::thread 参数指针 detach

std::thread 参数指针 detach

目录

thread函数定义

thread创建线程

 成员函数

传递临时参数作为线程对象的注意事项

解决方案1


thread函数定义

头文件:#include <thread>

在这里插入图片描述

(1). 默认构造函数,创建一个空的 thread 执行对象。
(2). 初始化构造函数,创建一个 thread对象,该 thread对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3). 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4). move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。

注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.

thread创建线程

一、用函数对象创建线程

二、用类对象创建线程

三、把某个类中的某个函数作为线程的入口地址

四、用lambda表达式创建线程

参考:(1条消息) c++ 多线程(2)创建线程对象的方法_一抹烟霞的博客-CSDN博客_多线程创建对象

  1. #include <iostream>
  2. #include <utility>
  3. #include <thread>
  4. #include <chrono>
  5. void f1(int n)
  6. {
  7. for (int i = 0; i < 5; ++i) {
  8. std::cout << "Thread 1 executing\n";
  9. ++n;
  10. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  11. }
  12. std::cout << "Thread 1 id = " << std::this_thread::get_id()<< std :: endl ;
  13. }
  14. void f2(int& n)
  15. {
  16. for (int i = 0; i < 5; ++i) {
  17. std::cout << "Thread 2 executing\n";
  18. ++n;
  19. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  20. }
  21. std::cout << "Thread 2 id = " << std::this_thread::get_id()<< std :: endl ;
  22. }
  23. class foo
  24. {
  25. public:
  26. void bar(int a)
  27. {
  28. for (int i = 0; i < 5; ++i) {
  29. std::cout << "Thread 3 executing\n";
  30. ++n;
  31. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  32. }
  33. std::cout << "Thread 3 id = " << std::this_thread::get_id()<< std :: endl ;
  34. std::cout << "a = " << a << std :: endl ;
  35. }
  36. void bar2()
  37. {
  38. for (int i = 0; i < 5; ++i) {
  39. std::cout << "Thread 33 executing\n";
  40. ++n;
  41. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  42. }
  43. std::cout << "Thread 33 id = " << std::this_thread::get_id()<< std :: endl ;
  44. }
  45. int n = 0;
  46. };
  47. class baz
  48. {
  49. public:
  50. baz(){std::cout << "I am in" << std :: endl ;}
  51. void operator()()
  52. {
  53. for (int i = 0; i < 5; ++i) {
  54. std::cout << "Thread 4 executing\n";
  55. ++n;
  56. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  57. }
  58. std::cout << "Thread 4 id = " << std::this_thread::get_id()<< std :: endl ;
  59. }
  60. void bar3()
  61. {
  62. for (int i = 0; i < 5; ++i) {
  63. std::cout << "Thread 44 executing\n";
  64. ++n;
  65. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  66. }
  67. std::cout << "Thread 44 id = " << std::this_thread::get_id()<< std :: endl ;
  68. }
  69. int n = 0;
  70. };
  71. int main()
  72. {
  73. int n = 0;
  74. foo f;
  75. baz b;
  76. std::thread t1; // t1 is not a thread
  77. std::thread t2(f1, n + 1); // pass by value
  78. std::cout << "t2 id = " << t2.get_id()<< std :: endl ;
  79. std::thread t3(f2, std::ref(n)); // pass by reference
  80. std::cout << "t3 id = " << t3.get_id()<< std :: endl ; //t3.join();
  81. std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
  82. std::cout << "t4 id = " << t4.get_id()<< std :: endl ;
  83. std::thread t5(&foo::bar, &f,1); // t5 runs foo::bar() on object f
  84. std::thread t7(&foo::bar2, &f); // t5 runs foo::bar() on object f
  85. std::thread t6(b); // t6 runs baz::operator() on object b
  86. t2.join();
  87. t4.join();
  88. t5.join();
  89. t7.join();
  90. t6.join();
  91. std::cout << "Final value of n is " << n << '\n';
  92. std::cout << "Final value of foo::n is " << f.n << '\n';
  93. }

 成员函数

指向当前线程std::this_thread
例如std::this_thread::get_id()

get_id   获取线程 ID
joinable检查线程是否可被 join
join Join 线程
detach  Detach 线程
swapSwap 线程
native_handle 返回 native handle
hardware_concurrency [static]  检测硬件并发特性

 detch

    称为分离线程函数,使用detach()函数会让线程在后台运行,即说明主线程不会等待子线程运行结束才结束

  1. #include <iostream>
  2. #include <thread>
  3. #include <windows.h>
  4. void func(){
  5. for (int i = 0; i < 100; ++i) {
  6. std::cout<<"thread::func"<<std::endl;
  7. }
  8. }
  9. int main() {
  10. std::thread my_thread(func);
  11. // Sleep(1);
  12. my_thread.detach();
  13. // my_thread.join();
  14. return 0;
  15. }

 由于使用的是detch函数,新线程与主线程分离,在detch函数执行完成,主线程main函数结束,my_thread对象销毁,还未执行一次打印线程也就结束了,这才造成这样的结果。下面我们加上Sleep(1);这句话,观察结果:

thread::func

thread::func

thread::func

thread::func

。。。。

传递临时参数作为线程对象的注意事项

线程(函数)的传入参数,引用&会失效,指针*还是会传递地址。

(在detach情况下发生,join下不会发生)

  1. #include <iostream>
  2. #include <thread>
  3. #include <string>
  4. using namespace std;
  5. void myprint(const int &i, char *pmybuf){
  6. //i并不是mavar的引用,实际是值传递
  7. //推荐改为const int i
  8. cout<<i<<endl;
  9. //指针在detach子线程时,还是指向原来的地址。但是此时地址已经被主线程释放会报错
  10. cout<< pmybuf <<endl;
  11. }
  12. int main(){
  13. int mvar=1;
  14. int &mvary=mvar;
  15. char mybuf[]="this is a test";
  16. thread my_thread(myprint, mvar, mybuf);//第一个参数是函数名,后两个参数是函数的参数
  17. // my_thread.join();//等待子线程执行结束
  18. my_thread.detach();
  19. cout<<"I love China"<<endl;
  20. return 0;
  21. }

myprint内容并不会被打印;

解决方案1

  1. #include <iostream>
  2. #include <thread>
  3. #include <string>
  4. using namespace std;
  5. class A{
  6. public:
  7. int m_i;
  8. A(int a):m_i(a){cout<<"gouzao fun run"<<endl;}
  9. A(const A &a):m_i(a.m_i){cout<<"copy gouzao fun run"<<endl;}
  10. ~A(){cout<<"xigou fun run"<<endl;}
  11. };
  12. void myprint(const int i, const A &pmybuf){
  13. cout<< &pmybuf <<endl;
  14. }
  15. int main(){
  16. int mvar=1;
  17. int mysec=12;
  18. // 如果是隐式转换,转换过程在子线程中执行,会有可能主线程执行完还没进行转换
  19. // 因此需要显式的转换,构造临时对象
  20. // 在线程声明时立刻执行构造
  21. // thread my_thread(myprint, mvar, mysec);//第一个参数是函数名,后两个参数是函数的参数
  22. thread my_thread(myprint, mvar, A(mysec));//第一个参数是函数名,后两个参数是函数的参数
  23. // my_thread.join();//等待子线程执行结束
  24. my_thread.detach();
  25. cout<<"I love China"<<endl;
  26. return 0;
  27. }
  1. gouzao fun run
  2. copy gouzao fun run
  3. copy gouzao fun run
  4. xigou fun run
  5. xigou fun run
  6. I love China
  7. 0xfd6f58
  8. xigou fun run
  9. 地址不一定能打印出来
  10. 两次拷贝构造函数:1、转换 2、值传递

1、线程(函数)的传入参数,引用&会失效,指针*还是会传递地址。因为主线程如果销毁了变量内存,子线程的运行就会出错,因此尽量不要在detach()的线程中用传递主线程中的指针
2、为了防止主线程先结束,detach()的线程还没构造,调用构造的时候要显示的调用类的拷贝构造,即为了防止主线程先结束,只有复制一份内存才行
3、想要传递真正的引用需要使用std::ref(param_nanm)

 join()没有这个问题。

  1. #include <iostream>
  2. #include <thread>
  3. #include <windows.h>
  4. void func(int *i,int j)
  5. {
  6. *i = *i+1;
  7. j = j+1;
  8. std::cout << "I in ="<< *i << std::endl;
  9. std::cout << "J in ="<< j << std::endl;
  10. }
  11. int main()
  12. {
  13. int i = 0;
  14. int j = 0;
  15. std::thread my_thread(func, &i,j);
  16. my_thread.join();
  17. std::cout << "I out ="<< i << std::endl;
  18. std::cout << "J out ="<< j << std::endl;
  19. system("pause");
  20. return 0;
  21. }

I in =1

J in =1

I out =1

J out =0

 参考:(1条消息) C++ 多线程(3)std::thread 详解_一抹烟霞的博客-CSDN博客_std 线程

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/153528
推荐阅读
相关标签
  

闽ICP备14008679号