2. C++マルチスレッド - 危険箇所分析

1. デタッチ使用時の解析


デタッチを使用する場合、子スレッドはポインターを渡してはなりません。


#include<iostream>
#include<thread>
using namespace std;

void my_print(const int& num1,const char* str) {
	cout << num1 << " " << str << endl;
}
//主进程结束后,才开始对子进程中的值进行拷贝。但是主进程释放了str1,子进程接收时会出现问题。
int main() {
	int num1 = 1;
	char str1[] = "hello,world!";
	thread obj1(my_print,num1,str1);
	obj1.detach();
	cout << "主进程结束运行" << endl;
	return 0;
}

一時クラス オブジェクトがパラメータとして使用され、スレッドに渡される場合、スレッドはコピー コンストラクターを呼び出して受信変数をコピーし、それをスレッドで使用します。

次のコードでは、参照を使用してクラス オブジェクトを受け取ります。参照を使用しない場合、システムはオブジェクトを再度構築するため、3 つの構築が行われ、時間が無駄になります。


#include<iostream>
#include<thread>
using namespace std;

class son_thread {
public:
	int m_a;
	son_thread(int a):m_a(a) {
		cout << "构造函数的调用" << endl;
	}
	~son_thread() {
		cout << "析构函数的调用" << endl;
	}
};

void my_print(const int a,const son_thread& st) {
	cout << a << " " << st.m_a << endl;
}
int main() {
	int num1 = 1;
	int num2 = 10;
	thread obj1(my_print, num1,son_thread(num2));
	obj1.detach();
	cout << "主进程结束运行" << endl;
	return 0;
}

2. 一時的なオブジェクト


1. オブジェクトが暗黙的な変換を採用する場合、オブジェクトは子スレッドで構築されます。

2. オブジェクトが明示的な変換を採用する場合、オブジェクトはメインスレッドで構築され、コピー コンストラクターが呼び出されます。

this_thread::get_id()---->スレッドのID番号を表示

知らせ:

暗黙的転送を使用する場合、子スレッドでクラスオブジェクトが構築されますが、このときメインスレッドは破壊され、メインスレッド内のローカル変数は解放されており、このときの動作は危険です。

明示的な構築が使用される場合、最初に一時オブジェクトがメインスレッドで構築され、次にメインスレッドでコピーとコピー構築が実行され、その後一時オブジェクトがメインスレッドで解放されます。


#include<iostream>
#include<thread>
using namespace std;
class son_thread {
public:
	int m_a;
	son_thread(int a) :m_a(a) {
		cout << "son_thread构造函数调用" << this_thread::get_id() << endl;
	}
	son_thread(const son_thread& base):m_a(base.m_a) {
		cout << "son_thread拷贝构造函数的调用" << this_thread::get_id()<< endl;
	}
	~son_thread() {
		cout << "son_thread析构函数调用" << this_thread::get_id()<< endl;
	}
};
void my_print(const son_thread& base) {
	cout << base.m_a << " my_print调用" << this_thread::get_id()<< endl;
}
int main() {
	int temp_a = 1;
	cout << "主线程的id:" << this_thread::get_id() << endl;
	//thread obj1(my_print, temp_a);
	thread obj1(my_print, son_thread(temp_a));
	obj1.join();
	cout << "主线程调用完毕:" << this_thread::get_id() << endl;

	return 0;
}

 3. スマート ポインターとクラス オブジェクトを渡す


クラス オブジェクトが渡されると、子スレッドはコピー コンストラクターを呼び出すため、子スレッドがクラス オブジェクトのメンバー変数を変更しても、メイン スレッドのオブジェクト メンバー変数は変更されません。

この時点で、 std::ref() 関数を使用できます。

unique_ptr スマート ポインターを渡す場合、std::move() を使用してスマート ポインターを変更できます。


#include<iostream>
#include<thread>
using namespace std;
class son_thread {
public:
	int m_a;
	son_thread(int a) :m_a(a) {
		cout << "son_thread构造函数调用" << this_thread::get_id() << endl;
	}
	son_thread(const son_thread& base) :m_a(base.m_a) {
		cout << "son_thread拷贝构造函数的调用" << this_thread::get_id() << endl;
	}
	~son_thread() {
		cout << "son_thread析构函数调用" << this_thread::get_id() << endl;
	}
};
void my_print(unique_ptr<int>temp_pt) {
	cout << *temp_pt << " my_print调用" << this_thread::get_id() << endl;
}
int main() {
	int temp_a = 1;
	cout << "主线程的id:" << this_thread::get_id() << endl;
	unique_ptr<int>u_pt(new int (100));
	thread obj1(my_print, std::move(u_pt));
	obj1.join();
	cout << "主线程调用完毕:" << this_thread::get_id() << endl;

	return 0;
}

4. クラス関数の関数をエントリ関数として使用する 


  


#include<iostream>
#include<thread>

using namespace std;
class son_thread {
public:
	int m_a;
	son_thread(int a) :m_a(a) {
		cout << "son_thread构造函数调用" << this_thread::get_id() << endl;
	}
	son_thread(const son_thread& base) :m_a(base.m_a) {
		cout << "son_thread拷贝构造函数的调用" << this_thread::get_id() << endl;
	}
	~son_thread() {
		cout << "son_thread析构函数调用" << this_thread::get_id() << endl;
	}
	void my_print(const int a ) {
		cout << a << " 类内函数的调用" << endl;
	}
};

int main() {
	cout << "主线程的id:" << this_thread::get_id() << endl;
	son_thread s1(10);
	thread obj1(&son_thread::my_print, s1, 100);
	obj1.join();
	cout << "主线程调用完毕:" << this_thread::get_id() << endl;
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_42813620/article/details/131026026