Skip to content

并发与多线程编程

约 397 个字 63 行代码 预计阅读时间 3 分钟

线程传值

  • 使用 detach() 分离两个线程可能会导致主线程在子线程结束前就跑完了
  • char*变量在线程中地址相同;使用string类型引用来解决;创建 m_thread 对象的时候复制一份临时变量

隐式转换和显示转换

  • 隐式转换,对象在子线程进行构造;如果detach后main线程先结束;直接失败
  • 显示转换,对象的构建过程和拷贝过程都是在主线程中完成的,这就确保了子线程在使用该参数时是安全的

  • 临时变量传参

  • 如果传递int这种简单类型,推荐使用值传递,不要用引用;
  • 如果传递类对象,要避免使用隐式类型转换,必须在代码中显式转换(相当于创建一个临时变量),然后在函数参数里,用引用来接(),虽然该方法安全,但不易理解,不推荐使用,
  • 不建议使用 detach(),用了非常容易出问题

传递类对象,智能指针

  • 参数是一个拷贝出来的对象,也就是说,在子线程中修改该对象中的成员,是不会传回给主线程的
  • 将“假”引用变为真引用;使用std::ref()
C++
class A {
 public:
  mutable int m_i; /* 添加mutable修饰,让m_i能被修改 */
  /* 构造函数,此处实际上是把一个int转成类型A的对象,又称为类型转换构造函数 */
  A(int a) : m_i(a) { cout << "[A::A(int a) exec]" << endl; }
  /* 拷贝构造函数 */
  A(const A &a) : m_i(a.m_i) { cout << "[A::A(const A &a) exec]" << endl; }
  /* 析构函数 */
  ~A() { cout << "[A::~A() exec]" << endl; }
};

void my_print(const A &pbuf) {
  pbuf.m_i = 66;
  cout << "my_print pbuf.m_i = " << pbuf.m_i << endl;
  return;
}

int main() {
  A obj(10);
  thread m_thread(my_print, ref(obj));
  m_thread.join();

  cout << "main obj.m_i = " << obj.m_i << endl;
  cout << "Hello World!" << endl;
  return 0;
}

用成员函数指针做线程函数

  • thread(argv[])
  • argv[0]:成员函数指针
  • argv[1]:A类对象
  • argv[2]:回调函数参数
C++
#include <iostream>
#include <thread>
using namespace std;

class A
{
public:
    int m_i;
    /* 构造函数,此处实际上是把一个int转成类型A的对象,又称为类型转换构造函数 */
    A(int a) : m_i(a) { cout << "[A::A(int a) exec]" << endl; }
    /* 拷贝构造函数 */
    A(const A &a) : m_i(a.m_i) { cout << "[A::A(const A &a) exec]" << endl; }
    /* 析构函数 */
    ~A() { cout << "[A::~A() exec]" << endl; }
    /* 成员函数做线程回调函数 */
    void thread_work(int num)
    {
        cout << "thread_work exec" << endl;
    }
};

int main()
{
    A obj(10);
    int var = 15;
    /* 参数一:成员函数指针 */
    /* 参数二:A类对象 */
    /* 参数三:回调函数参数 */
    /* 参数..:回调函数参数 */
    thread m_thread(&A::thread_work, obj, var);         /* obj对象会被拷贝一份传入子线程 */
    // thread m_thread(&A::thread_work, ref(obj), var); /* obj对象直接传入子线程 */
    // thread m_thread(&A::thread_work, &obj, var);     /* 与std::ref()一样,obj对象也是直接传入子线程(&obj为取地址) */
    m_thread.join();

    cout << "Hello World!" << endl;
    return 0;
}