同時実行操作の待機使い捨てイベント


いくつかのバックグラウンドスレッドで計算を完了する必要がある場合があります.これらの計算は往々にして使い捨てであり、スレッドの計算が完了すると終了します.この場合、条件変数を使用することができますが、少しもったいないので、一度だけ結果を得る必要があります.C++標準ライブラリにはヘッダファイルがあり、「未来」をイメージし、将来の計算結果を取得します.
std::asyncを使用して非同期タスクを開始します.std::futureオブジェクトを使用して、非同期タスクが返す結果を格納します.このオブジェクトは結果を格納します.結果が必要な場合はget()メソッドを呼び出すだけです.この場合、まだ計算が完了していない場合は、現在のスレッドがブロックされます.
#include<future>
#include<iostream>


int find_the_answer_to_ltuae();
void do_other_sutff();
int main()
{
	std::future<int> the_answer = std::async(find_the_answer_to_ltuae);
	do_other_sutff();
	std::cout << "The answer is " << the_answer.get() << std::endl;
	return 0;
}
int find_the_answer_to_ltuae()
{

	return 10;
}
void do_other_sutff()
{
	std::cout << "do_other_sutff " << std::endl;
}

スレッドのように関数にパラメータを渡すことができます
#include<future>
#include<iostream>
#include<string>

struct X
{
	void foo(int, std::string const&);
	std::string bar(std::string const&);
};
X x;
auto f1 = std::async(&X::foo, &x, 32, "hello");//p->foo(42,"hello")。p &x
auto f2 = std::async(&X::bar, x, "goodbye");//tmp.bar("goodbye")。x tmp

struct Y
{
	double operator()(double);
};
Y y;
auto f3 = std::async(Y(), 3.141);//tem(3.141),tmp Y() move-constructed
auto f4 = std::async(std::ref(y), 2.718);//y(2.718)
X baz(X&);
std::async(baz, std::ref(x));//  baz
class move_only
{
public:
	move_only();
	move_only(move_only&&);
	move_only(move_only const&) = delete;
	move_only& operator=(move_only&&);
	move_only& operator=(move_only const&)=delete;
	void operator()();
};
auto f5 = std::async(move_only());//        

パラメータを渡すことで、新しいスレッドを起動するか、いつ新しいスレッドを起動するかを決定できます.
auto f6 = std::async(std::launch::async, Y(), 1.2);//       
auto f7 = std::async(std::launch::deferred, baz, std::ref(x));//  wait get    
auto f8 = std::async(
	std::launch::deferred | std::launch::async,
	baz, std::ref(x));//      
auto f9 = std::async(baz, std::ref(x));
f7.wait();//  f7       

taskとfutureを組み合わせる
std::packaged_を使用できます.task<>とfutureが結合しています.std::package_をアクティブにするとtask<>の場合、futureの関数が呼び出されます.関数は、結果が関連付けられているデータを返します.
std::package_task<>のパラメータは、関数署名(関数ポインタ定義など)です.例えばvoid()は、戻り値がなく、パラメータがない関数を表す.int(std::sgring&,double*)は、関数の戻りタイプがint、パラメータがstring参照、doubleタイプポインタを表します.stdを定義すると::package_task<>オブジェクトの場合、パラメータと戻りタイプを指定する必要があります.
std::future<>の戻りタイプはメンバー関数get_を介してfuture()を取得します.
多くのGUIフレームワークでは、特定のスレッドからGUIを更新することが要求される.スレッドがGUIを更新する場合は、GUIスレッドにメッセージを送信する必要があります.std::package_からtaskはこの問題を解決します.
 
#include<deque>
#include<mutex>
#include<future>
#include<thread>
#include<utility>

std::mutex m;
std::deque<std::packaged_task<void()> > tasks;
	
bool gui_shutdown_message_received();
void get_and_process_gui_message();

void gui_thread()//GUI  
{
	while(!gui_shutdown_message_received())//  GUI    
	{
		get_and_process_gui_message();//  GUI    
		std::packaged_task<void()> task;//    
		{
			std::lock_guard<std::mutex> lk(m);
			if(tesks.empty())//        ,  task()
				continue;
			task=std::move(tasks.front());
			tasks.pop_front();//    
		}
		task();//  task
	}
}

std::thread gui_bg_thread(gui_thread);
template<typename Func>
std::future<void> post_task_for_gui_thread(Func f)
{
	std::package_task<void()> task(f);//  task
	std::future<void> res=task.get_future();
	std::lock_guard<std::mutex> lk(m);
	tasks.push_back(std::move(task));// task    
	return res;
}