zoukankan      html  css  js  c++  java
  • C++多线程基础学习笔记(三)

    一、detach()大坑

    上一篇随笔(二)中提到detach()是用来分离主线程和子线程的,那么需要考虑一个问题,就是如果主线程跑完了,主线程中定义的变量就会被销毁(释放内存),这时回收变量仍作为参数传入子线程,那么就会出现问题,下面用一个例子详细说明。

     1 #include <iostream>
     2 #include <string>
     3 #include <thread>
     4 using namespace std;
     5 
     6 void MyThread(const int& a, char* str)
     7 {
     8     cout << a << endl;
     9     cout << str << endl;
    10 }
    11 int main()
    12 {
    13     
    14     int n = 20;
    15     char str_m[] = "hello wrold";
    16     thread MyThreadObj(MyThread, n, str_m);
    17     if (MyThreadObj.joinable())
    18     {
    19         MyThreadObj.detach();
    20     }
    21     cout << "main_thread" << endl;
    22     system("pause");
    23     return 0;
    24 }

    由监视图可知,实参n和形参a的地址并不同,所以实际是值传递,并因此最好不要用引用,直接用值传递就行了。

    主线程的str_m和str的地址却相同,那么当子线程和主线程分离时,就会出现问题。这里讲一个改进的方法,把形参char* str改成const string& str,即把传进来的参数隐式地转换成一个(构造了)string对象,会发现主线程的str_m和子线程形参str的地址是不同的,但实际上问题还是存在,如果在在传递主线程的参数str_m前,str_m就被回收了,一个被回收的变量作为参数结果可想而知。所以还要再改多一步,就是在main()中实参str_m改成string(str_m),先构造一个string对象,再将这个对象作为参数传入子线程,这时又会有疑问,难道不会出现在string(str_m)前str_m就被系统回收了吗?答案是不会的,测试方法这里不细说了。

    下面是改进后的代码

     1 #include <iostream>
     2 #include <string>
     3 #include <thread>
     4 using namespace std;
     5 
     6 void MyThread(int a, const string& str)
     7 {
     8     cout << a << endl;
     9     cout << str << endl;
    10 }
    11 int main()
    12 {
    13     
    14     int n = 20;
    15     char str_m[] = "hello wrold";
    16     thread MyThreadObj(MyThread, n, string(str_m));
    17     if (MyThreadObj.joinable())
    18     {
    19         MyThreadObj.detach();
    20     }
    21     cout << "main_thread" << endl;
    22     system("pause");
    23     return 0;
    24 }

     二、std::this_thread::get_id()

    线程id,每个线程都有自己的线程id,各个id都不同,获取线程id方法为std::this_thread::get_id()

     1 #include <iostream>
     2 #include <string>
     3 #include <thread>
     4 using namespace std;
     5 class CA
     6 {
     7 public:
     8     int a;
     9     CA(int m) :a(m) 
    10     {
    11         cout << "构造函数执行 " << endl;
    12     }
    13     CA(const CA&m) :a(m.a) 
    14     {
    15         cout << "拷贝构造函数执行 " << endl;
    16     }
    17 };
    18 void MyThread(const CA&cc) 
    19 {
    20     cout << "子线程id:" << this_thread::get_id() << endl;
    21     cout << cc.a << endl;
    22 }
    23 int main()
    24 {
    25     cout << "主线程id:" << this_thread::get_id() << endl;
    26     CA ca(10);
    27     thread mythreadObj(MyThread,ca);
    28     mythreadObj.join();
    29     system("pause");
    30     return 0;
    31 }

    三、std::ref()

    上述代码运行可知,如果向子线程传入一个对象,会调用拷贝构造函数,这时用detach()是安全的,但是如果想要通过子线程来修改主线程对象的数据是不允许的,可以把18行的const去掉试试,是会报错的,那么可以用std::ref()来使这个对象得以修改。(当然,18行处也可以改成void MyThread(CA cc),这样也是可以修改,但是修改的只是拷贝的对象,对主线程的对象没有影响,而且会调用两次拷贝构造函数,浪费内存)

     1 #include <iostream>
     2 #include <string>
     3 #include <thread>
     4 using namespace std;
     5 class CA
     6 {
     7 public:
     8     int a;
     9     CA(int m) :a(m) 
    10     {
    11         cout << "构造函数执行 " << endl;
    12     }
    13     CA(const CA&m) :a(m.a) 
    14     {
    15         cout << "拷贝构造函数执行 " << endl;
    16     }
    17 };
    18 void MyThread(CA& cc) 
    19 {
    20     cc.a++;
    21     cout << "子线程id:" << this_thread::get_id() << endl;
    22     cout << "my_thread " <<"ca.a:" << cc.a << endl;
    23 }
    24 int main()
    25 {
    26     cout << "主线程id:" << this_thread::get_id() << endl;
    27     CA ca(10);
    28     thread mythreadObj(MyThread, ref(ca));
    29     cout << "main_thread " << "ca.a:" << ca.a << endl;
    30     mythreadObj.join();
    31     system("pause");
    32     return 0;
    33 }

    由结果可知,并不会调用拷贝构造函数,在子线程中操作的是主线程中的对象。这时需要注意了,如果用detach(),就不安全了。还是那个问题,对已经释放的变量进行非法操作必定带来隐患。

  • 相关阅读:
    缓慢变化纬的解决方法
    行转列且有序
    异常处理
    继承
    js的隐式转化
    初步了解微任务
    axios中断请求AbortController
    Vue解决V-HTML指令潜在的XSS攻击('v-html' directive can lead to XSS attack vue/no-v-html)
    axios下载后台传过来的流文件并设置下载文件名(如excel)
    axios异步获取文件流数据
  • 原文地址:https://www.cnblogs.com/main404/p/11161671.html
Copyright © 2011-2022 走看看