プログラミングメモ →目次

並列パターン ライブラリ (PPL)における取り消し処理

タスク グループ、構造タスク グループのcancel()メソッドで実行中の並列処理を中断する方法、および、try-catch文で中断する方法をメモします。

下記のソースでは、配列にあるデータをサーチする処理として、タスク グループの使い方、および並列処理中断方法を記述します。

// parallel_cancel.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include <windows.h>
#include <ppl.h>
#include <iostream>

using namespace std;
using namespace Concurrency;

//配列を宣言します。
int dat[10000];

//時間テストの為に、遅延を入れます。
void delay()
{
	for (int i = 0; i < 20000; i ++);
}

//シリアルのサーチ処理。
int SearchDataSeiral(int from, int to, int key)
{
	for (int i = from; i < to; i ++)
	{
		delay();
		if (key == dat[i])
			return i;
	}
	return INT_MAX;
}

//タスクグループで、2つの処理を同時にさせます。
int SearchData_TaskGroup(int key)
{
	int n1; 
	int n2;
	task_group tg;
	tg.run([&](){n1 = SearchDataSeiral(0,5000, key);});
	tg.run([&](){n2 = SearchDataSeiral(5000,10000, key);});
	tg.wait();
	return min(n1, n2);
}

//構造タスクグループで、2つの処理を同時にさせます。
int SearchData_StructuredTaskGroup(int key)
{
	int n1; 
	int n2;
	structured_task_group  stg;
	auto task1 = make_task([&](){n1 = SearchDataSeiral(0,5000, key);});
	stg.run(task1);
	auto task2 = make_task([&](){n2 = SearchDataSeiral(5000,10000, key);});
	stg.run(task2);
	stg.wait();
	return min(n1, n2);
}

//構造タスクグループ内で、parallel_forを実行します。
//ある条件で、構造タスクグループのcancel()を呼び出して、処理をキャンセルさせます。
int SearchData_StructuredTaskGroup_Cancel(int key)
{
	structured_task_group stg;
	int n; 

	task_group_status status = stg.run_and_wait([&] 
	{
		parallel_for(0, 10000, [&](int i) 
		{
      		delay();
			if (key == dat[i])
			{
				n = i;
				stg.cancel();
			}
		});
	});

	// Print the task group status.
	cout << "The task group status is: ";
	switch (status)
	{
	case not_complete:
		cout << L"not complete." << endl;
		n = INT_MAX;
		break;
	case completed:
		cout <<"completed." << endl;
		n = INT_MAX;
		break;
	case canceled:
		cout << "canceled." << endl;
		break;
	default:
		cout << "unknown." << endl;
		n = INT_MAX;
		break;
	}
	return n;
}

//try-catchで、parallel_forをキャンセルさせます。
int SearchData_Parallel_Try_Catch_Cancel(int key)
{
	int n = INT_MAX;
	try
	{
		parallel_for(0, 10000, [&](int i) 
		{
			// Throw an exception to cancel the task when i is 50.
     		delay();
			if (key == dat[i])
			{	
				throw i;
			}
		});
	}
	catch (int inx)
	{
		cout << "Caught " << inx << endl;
		n = inx;
	}
	return n;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//配列初期化(乱数)
	srand(::GetTickCount());
	for (int i = 0; i < 10000; i ++)
		dat[i] = abs(rand()) % 2000;

	//以下は、各関数のテストです。

	DWORD begin = 0, end = 0;
	int result = 0;
	begin = ::GetTickCount();
	result = SearchData_TaskGroup(1000);
	end = GetTickCount();
	cout << "SearchData_TaskGroup" << endl;
	cout << end - begin<<" ms "<< result << endl;

	begin = 0, end = 0, result = 0;
	begin = ::GetTickCount();
	result = SearchData_StructuredTaskGroup(1000);
	end = GetTickCount();
	cout << "SearchData_StructuredTaskGroup" << endl;
	cout << end - begin<<" ms "<< result << endl;


	begin = 0, end = 0, result = 0;
	begin = ::GetTickCount();
	result = SearchData_StructuredTaskGroup_Cancel(1000);
	end = GetTickCount();
	cout << "SearchData_StructuredTaskGroup_Cancel" << endl;
	cout << end - begin<<" ms "<< result << endl;


	begin = 0, end = 0, result = 0;
	begin = ::GetTickCount();
	result = SearchData_Parallel_Try_Catch_Cancel(1000);
	end = GetTickCount();
	cout << "SearchData_Parallel_Try_Catch_Cancel" << endl;
	cout << end - begin<<" ms "<< result << endl;

	getchar();
	return 0;
}

/*--------------------------------------
Output:

SearchData_TaskGroup
157 ms 982
SearchData_StructuredTaskGroup
156 ms 982
The task group status is: canceled.
SearchData_StructuredTaskGroup_Cancel
78 ms 982
Caught 982
SearchData_Parallel_Try_Catch_Cancel
63 ms 982
*/