• c++11线程间参数传递


    传递临时对象作为线程参数

    创建的工作线程不止一个,线程根据编号来确定工作内容。每个线程都需要知道自己的编号。线程中有很多容易犯错的写法

    例子1

    多线程需要执行的函数:

    void my_print(const int &i, char* p_mybuff)
    {
        cout << i << endl;
        cout << p_mybuff << endl;
        return ;
    }

     主函数的写法

    int mvar = 1;
    int& mvary = mvar;
    char mybuf[] = "this is a test!";
    thread myobj(my_print, mvar, mybuf);
    myobj.join();
     
    cout << "Main Thread!!!" << endl;

     解释:注意陷阱!!!引用和指针的变量传参。

    引用:表面看起来似乎正确,但是细节上有很多地方需要注意的,如果把join()改成detach(),然后主线程和子线程分别执行,那么可能出现主线程执行完了,但是传递进去的参数(引用形式)的资源已经被释放了,有没有可能出现错误?:

    myobj.detach()

      在创建thread对象的时候,做了一个复制,把值复制进去了,所以不是一个真引用,实际是值传递,不会出现资源释放的错误。但是反过来想,那么主线程的变量的值并不会改变。

    指针:如果传递的参数是指针,第二个参数不安全,如果用detach()执行线程的时候,不推荐用“引用”,指针绝对会有问题!

    正确的用法是什么样:不传引用,如果要传字符串的情况。

    char* p_mybuff 改成 const string &p_mybuff ,确实不指向于同一块内存,什么时候出现了变量类型的转换?事实上存在主函数执行完了,p_mybuff 都被回收了,系统才用p_mybuff 去转换string

    thread myobj(my_print, mvar, string(mybuf));

      如果用一个string 去强制类型转换,生成一个临时对象,此时的临时对象会绑定到p_mybuff上。在创建线程的时候,构造临时变量的方法传递参数是可行的,此时也会调用一次构造函数,此时detach也能正确运行。为了防止主线程退出,子线程内存的非法引用。

    1) 对传递int,直接用值传递。

    2) 如果传递类对象,避免隐式类型转换。全部都在创建线程的时候就构建出临时对象,在函数参数里用引用来接收传递的函数。否则系统还会多构造一次函数,造成不必要的浪费。

    3) 主线程中类型转换,那么A(mysecondpar) 这一步由主线程操作

    thread myobj(myprint, mvar, A(mysecondpar));

    thread myobj(myprint, mvar, mysecondpar);

    4) 建议不使用detach,用join

    传递临时对象作为线程参数

    线程ID:在操作系统的层面需要调度线程,有一个线程ID,以及线程ID的文件描述符,用来管理这个线程的资源分配。在线程之间需要调度,所以也有优先级的概念。每个线程对应一个ID,线程ID可以用C++标准库里面的函数来获取 std::this_thread::get_id()。

    传参函数给线程的时候,参数入口都是const,在函数中const不能修改,如果需要修改变量,就在初始化的时候“mutable”。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,但是在多线程里面也有问题,如果真的要修改值,那么就使用std:ref(),这个ref和在C#里面是类似的,将方法内的变量改变后带出方法外,用std:ref(),真正地把变量传进去。

     完整的代码:

    #include "pch.h"
    #include <iostream>
    #include <thread>
     
    using namespace std;
     
    class person {
    public:
        int m_age;
        person(int a) :m_age(a) {
            cout << "person 的构造函数,进程为:" << std::this_thread::get_id()<<endl;
        }
        person(const person &p) :m_age(p.m_age) {
            cout << "person 的复制构造函数 " << std::this_thread::get_id() << endl;
        }
        ~person() {
            cout << "person的析构函数 " << std::this_thread::get_id() << endl;
        }
     
    };
    void myprin(const int &num, char *p[]) {
        cout << "现在的线程是: " << std::this_thread::get_id() << endl;
        cout << "传入的参数是:" << endl;
        cout << num << "  " << p << endl;
    }
    void print_class(person p)
    {
        cout << "现在的线程是: " << std::this_thread::get_id() << endl;
        cout << "print class: " << p.m_age << endl;
    }
     
    int main()
    {
     
        std::cout << "主线程: "<< std::this_thread::get_id()<<endl; 
         
        int num = 1;
        //person student(num);
        thread obj(print_class, person(10));
         
     
    }

      

    传递成员函数到线程中

    将类的成员函数传递到线程中。

    std::thread myobj(&classA::method, para1, para2,..);
    myobj.join();

      

     

    classA::method就是一个函数。
  • 相关阅读:
    Spring MVC 3 深入总结
    精益之识别和消除研发过程中浪费的思路和模式
    怎样区分直连串口线和交叉串口线?
    UVA 10557 XYZZY
    概率论 —— 分析计算机系统和网络的可靠性和通用性
    概率论 —— 分析计算机系统和网络的可靠性和通用性
    Sift中尺度空间、高斯金字塔、差分金字塔(DOG金字塔)、图像金字塔
    鲁迅先生的话
    鲁迅先生的话
    辛词
  • 原文地址:https://www.cnblogs.com/xietianjiao/p/13386558.html
Copyright © 2020-2023  润新知