zoukankan      html  css  js  c++  java
  • C++并发与多线程学习笔记--参数传递详解

    • 传递临时对象
      • 陷阱
      • 总结
    • 临时对象作为线程参数
      • 线程id的概念
      • 临时对象构造时的抓捕
    • 成员函数指针做线程函数

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

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

    例子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就是一个函数。
    

      



  • 相关阅读:
    将Nginx添加到windows服务中
    springboot使用redis管理session
    GIT常用命令
    阻止360、谷歌浏览器表单自动填充
    谈谈对Spring IOC的理解
    同一个Nginx服务器同一端口配置多个代理服务
    LeetCode 653. Two Sum IV
    109. Convert Sorted List to Binary Search Tree(根据有序链表构造平衡的二叉查找树)
    108. Convert Sorted Array to Binary Search Tree(从有序数组中构造平衡的BST)
    LeetCode 236. Lowest Common Ancestor of a Binary Tree(二叉树求两点LCA)
  • 原文地址:https://www.cnblogs.com/rynerlute/p/11795565.html
Copyright © 2011-2022 走看看