std :: futureの共有およびアトミック操作は、マルチスレッド取得の処理と共有データの書き込みに使用されます

1. std :: futureは
、非同期スレッド計算結果の戻り値を取得するために使用されます。future
のget関数の設計はmoveセマンティクス(move)であり、move後にクリアされるため、データは1回しか取得できません。

int mythread()
{
    
    
cout<<"mythread starat ,ThreadID is"<<std::this_thread::get_id()<<endl;
std::chrono::millseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread end,ThreadID is<<std::this_thread::get_id()<<endl; 
return 5;
}

int main()
{
    
    
cout<<"main thread start,threadId is "<<std::this_thread::get_id()<<endl;
std::future<int> result=std::async(thread);
cout<<"Go on!"<<endl;
//The program will be stuck,until the result get the return value. 
cout<<result.get()<<endl;
cout<<"Main finish"<<endl;

return 0;
}

2.std:future_status :: timeout&std :: future_status :: readyは
列挙型であり、スレッドが時間外に実行されて完了したかどうかをマークおよび判別するために使用されます

int mythread()
{
    
    
cout<<"mythread starat ,ThreadID is"<<std::this_thread::get_id()<<endl;
std::chrono::millseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread end,ThreadID is<<std::this_thread::get_id()<<endl; 
return 5;
}

int main()
{
    
    
cout<<"main thread start,threadId is "<<std::this_thread::get_id()<<endl;
std::future<int> result=std::async(mythread);
cout<<"Go on!"<<endl;
//1.main thread wait 8 seconds
std::future_status mstatus=result.wait_for(std::chrono::seconds(8));
//In 8 seconds,mythread finish & return the value ,mstatus != timeout,=ready

//2.main thread wait 1 seconds
//std::future_status mstatus=result.wait_for(std::chrono::seconds(1));
//In 1 seconds,mythread doesn't finish & return the value ,mstatus == timeout


if(mstatus==future_status::timeout)
{
    
    
	cout<<"Mythread doesn't finish"<<endl;
}
else if(mstatus==future_status::ready)
{
    
    
	cout<<"Mythread finish"<<endl;
	cout<<result.get()<<endl;
}

return 0;
}

3.future_status :: deferred
delayはmythreadの実行をトリガーしますが、メインスレッドでmythread関数を実行することは、関数呼び出しと同等です。

int main()
{
    
    
cout<<"main thread start,threadId is "<<std::this_thread::get_id()<<endl;
std::future<int> result=std::async(std::launch::deferred,mythread);
cout<<"Go on!"<<endl;
//1.main thread wait 8 seconds
std::future_status mstatus=result.wait_for(std::chrono::seconds(8));
//In 8 seconds,mythread finish & return the value ,mstatus != timeout,=ready

if(mstatus==future_status::timeout)
{
    
    
	cout<<"Mythread doesn't finish"<<endl;
}
else if(mstatus==future_status::ready)
{
    
    
	cout<<"Mythread finish"<<endl;
	cout<<result.get()<<endl;
}

else if(mstatus==std::future_status::deferred)//延迟
{
    
    
	//if async的第一次参数被设置为deferred,则成立
	cout<<"Thread defer<<endl;
	cout<<result.get()<<endl;//当运行到get时,mythread才开始执行。wait_for失效
}


return 0;
}

4. std :: shared_future
もクラステンプレートです。
std :: futureのget()関数はデータを移動します。
std :: shared_futureのget()関数はデータをコピーします。複数のスレッド(mythread2&mythread3)がデータを取得できます。

(1)共有データが存在するかどうかを確認してから共有する

//判断型
int mythread(int mypar)
{
    
    
	cout << "mythread starat ,ThreadID is" << std::this_thread::get_id() << endl;
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);
	cout << "The para is " << mypar << endl;
	cout << "mythread end,ThreadID is"<<std::this_thread::get_id()<<endl; 
	return 5;
}

void mythread2(std::shared_future<int>& tmpf)
{
    
    
	cout << "mythread2 start, threadID is" << std::this_thread::get_id() << endl;
	auto result = tmpf.get();
	cout << "mythread2 result=" << result << endl;
}

void mythread3(std::shared_future<int>& tmpf)
{
    
    
	cout << "mythread3 start, threadID is" << std::this_thread::get_id() << endl;
	auto result = tmpf.get();
	cout << "mythread3 result=" << result << endl;
}

int main()
{
    
    
	cout << "main thread start,threadId is " << std::this_thread::get_id() << endl;
	std::packaged_task<int(int)>mypt(mythread);
		std::thread t1(std::ref(mypt), 101);
	t1.join();
	std::future<int>result = mypt.get_future();

	bool ifcanget = result.valid();//vaild判断result中是否含有值,有true,没有false
	if (ifcanget == true)
	{
    
    
		//std::shared_future<int>result_s(std::move(result));//通result.share()
		std::shared_future<int>result_s(result.share());//把result的值移动到result_s中去
		auto mythreadresult = result_s.get();
		std::thread t2(mythread2, ref(result_s));
		t2.join();
		std::thread t3(mythread3, ref(result_s));
		t3.join();
	}

	return 0;
}

(2)共有データが直接共有されているかどうかを判断しないでください。

//不判断,直接share。
int main()
{
    
    
	cout << "main thread start,threadId is " << std::this_thread::get_id() << endl;
	std::packaged_task<int(int)>mypt(mythread);
	std::thread t1(std::ref(mypt), 101);
	t1.join();
	//std::future<int>result = mypt.get_future();

	std::shared_future<int> result_s(mypt.get_future());
	auto mythreadresult = result_s.get();

	thread t2(mythread2, std::ref(result_s));
	thread t3(mythread3, std::ref(result_s));
	t2.join();
	t3.join();
	cout << "Result_s.get() is" << mythreadresult << endl;

	return 0;
}

5. std ::アトミック
アトミック操作(分離不可能な操作)、ロックテクノロジのないマルチスレッド同時実行モードマルチスレッドで中断されないプログラム実行フラグメント。
ミューテックスロックは一般にコードセグメント用ですがアトミック操作は変数用であり、コードセグメント用でありません。
通常、送受信されたデータの数をカウントするために使用されます。

問題コード、2スレッド実行が同じ関数を使用してグローバル変数に対して大規模なデータ操作を実行する場合、スレッドスライスの切り替えのために、期待される操作を完全に実行できず、データが不足します。(中間値の問題の読み取り)
g_count最終結果は2000000になると予想され、実際の結果は約130,000です。

static int g_count=0;
void mythread()
{
    
    
	for (int i = 0; i < 1000000; i++)
	{
    
    
		g_count++;
	}
}


int main()
{
    
    
	std::thread t1(mythread);
	std::thread t2(mythread);

	t1.join();
	t2.join();

	cout << "G_count is " << g_count << endl;
	return 0;
}

中央値?
テストコードを作成しました。
結果は、スレッド1またはスレッド2に関係なく、9999に追加できることを示していますが、結果は2Wではありません。次に、中間値の問題は、スレッドが切り替えられると、1スレッドのg_countが200、タイムスライスが2スレッドに切り替えられ、2スレッドのg_countが100にカウントされ、タイムスライスが切り替えられることです。ただし、現時点では、1スレッドのg_coutカウントは100から始まり、100カウントが失われます。これは中間値の問題です。

std::mutex g_mutex;
void mythread()
{
    
    
	for (int i = 0; i < 10000; i++)
	{
    
    
		//cout << "thread is" << _threadid << ", i is" << i << endl;
		
		//g_mutex.lock();
		g_count++;
		if (i > 9990)
		{
    
    
			cout << "ThreadId is " << _threadid << ", i is " << i << endl;
		}
		//g_mutex.unlock();
	}
}

int main()
{
    
    
	std::thread t1(mythread);
	std::thread t2(mythread);

	t1.join();
	t2.join();

	

	cout << "G_count is " << g_count << endl;
	return 0;
}

解決策1:ミューテックス、低効率

static int g_count=0;
std::mutex g_mutex;
void mythread()
{
    
    
	for (int i = 0; i < 1000000; i++)
	{
    
    
		g_mutex.lock();
		g_count++;
		g_mutex.unlock();
	}
}


int main()
{
    
    
	std::thread t1(mythread);
	std::thread t2(mythread);

	t1.join();
	t2.join();

	cout << "G_count is " << g_count << endl;
	return 0;
}

解決策2:アトミック操作std :: atomic、高効率
C ++ 11、クラステンプレート。

std::atomic<int> g_count = 0;
void mythread()
{
    
    
	for (int i = 0; i < 1000000; i++)
	{
    
    
		g_count++;
	}
}
int main()
{
    
    
	std::thread t1(mythread);
	std::thread t2(mythread);

	t1.join();
	t2.join();

	cout << "G_count is " << g_count << endl;
	return 0;
}

アトミック操作は双眼オペレーターをサポートしていません!
+、-、*、/はサポートされておらず、異常なデータが返されます。

void mythread()
{
    
    

	for (int i = 0; i < 100000; i++)
	{
    
    
		g_count++;//输出200000,正确
		g_count += 1;//输出200000,正确
		g_count = g_count + 1;//错误,不是所有运算符都支持原子操作
		//一般原子操作,针对++,--,+=,&=,|=是支持的
	}
}

ブール型アトミックは
、コードセグメントを制御するために使用されます

std::atomic<bool>g_ifend = false;//防止多线程同时写入数据时乱套。
void mythread()
{
    
    
	std::chrono::milliseconds dura(1000);
	while (g_ifend == false)
	{
    
    
		//如果为false,则系统未要修此线程退出,线程继续执行。
		cout << "Thred ID is " << _threadid << endl;
		std::this_thread::sleep_for(dura);
	}
	cout << "Thread  end, ID is " << _threadid << endl;
	return;
}
int main()
{
    
    
	std::thread t1(mythread);
	std::thread t2(mythread);
	
	std::chrono::seconds dura(5);
	std::this_thread::sleep_for(dura);
	//因为是线程中运行的是while循环,如果结束条件在join()语句下方,那么会因为joim阻塞语句,产生死循环
	//所以当线程需要,函数外判定结束时,判定语句一定要在join之前执行。
	g_ifend = true;//让原子对象,自行了断。

	t1.join();
	t2.join();

	return 0;
}

結果グラフ

おすすめ

転載: blog.csdn.net/guanxunmeng8928/article/details/108559570