チュートリアル: 既存のコードを改変して軽量タスクを使用する
ここでは、Windows API を使用する既存のコードを改変して、軽量タスクを使用するスレッドを作成および実行する方法について説明します。
軽量タスクとは、concurrency::Scheduler オブジェクトまたは concurrency::ScheduleGroup オブジェクトから直接スケジュールするタスクです。 軽量タスクは、既存のコードを改変してコンカレンシー ランタイムのスケジュール機能を使用する場合に有用です。
前提条件
このチュートリアルを開始する前に、「タスク スケジューラ (コンカレンシー ランタイム)」を読んでください。
例
Windows API を使用してスレッドを作成および実行する一般的な方法を次の例に示します。 この例では、CreateThread 関数を使用して、MyThreadFunction
を別個のスレッドで呼び出しています。
最初のコード
// windows-threads.cpp
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#define BUF_SIZE 255
DWORD WINAPI MyThreadFunction(LPVOID param);
// Data structure for threads to use.
typedef struct MyData {
int val1;
int val2;
} MYDATA, *PMYDATA;
int _tmain()
{
// Allocate memory for thread data.
PMYDATA pData = (PMYDATA) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(MYDATA));
if( pData == NULL )
{
ExitProcess(2);
}
// Set the values of the thread data.
pData->val1 = 50;
pData->val2 = 100;
// Create the thread to begin execution on its own.
DWORD dwThreadId;
HANDLE hThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
pData, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
if (hThread == NULL)
{
ExitProcess(3);
}
// Wait for the thread to finish.
WaitForSingleObject(hThread, INFINITE);
// Close the thread handle and free memory allocation.
CloseHandle(hThread);
HeapFree(GetProcessHeap(), 0, pData);
return 0;
}
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
PMYDATA pData = (PMYDATA)lpParam;
// Use thread-safe functions to print the parameter values.
TCHAR msgBuf[BUF_SIZE];
StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"),
pData->val1, pData->val2);
size_t cchStringSize;
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
DWORD dwChars;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
return 0;
}
この例を実行すると、次の出力が生成されます。
Parameters = 50, 100
コンカレンシー ランタイムを使用して同じタスクを実行するようにこのコード例を改変する手順を次に示します。
軽量タスクを使用するように例を改変するには
- ヘッダー ファイル concrt.h の
#include
ディレクティブを追加します。
#include <concrt.h>
using
名前空間のconcurrency
ディレクティブを追加します。
using namespace concurrency;
MyThreadFunction
の宣言を次のように変更して、__cdecl
呼び出し規約を使用すると共に、void
を返します。
void __cdecl MyThreadFunction(LPVOID param);
MyData
構造体を変更して、タスクが完了したことをメイン アプリケーションに通知する concurrency::event オブジェクトを含めます。
typedef struct MyData {
int val1;
int val2;
event signal;
} MYDATA, *PMYDATA;
CreateThread
呼び出しを concurrency::CurrentScheduler::ScheduleTask メソッドの呼び出しで置き換えます。
CurrentScheduler::ScheduleTask(MyThreadFunction, pData);
- タスクの完了を待つために、
WaitForSingleObject
呼び出しを concurrency::event::wait メソッドの呼び出しで置き換えます。
// Wait for the task to finish.
pData->signal.wait();
CloseHandle
呼び出しを削除します。手順 3. に合わせて、
MyThreadFunction
の定義のシグネチャを変更します。
void __cdecl MyThreadFunction(LPVOID lpParam)
MyThreadFunction
関数の末尾で concurrency::event::set メソッドを呼び出して、タスクが完了したことをメイン アプリケーションに通知します。
pData->signal.set();
return
ステートメントをMyThreadFunction
から削除します。
完成したコード
次の完成版の例に、軽量タスクを使用して MyThreadFunction
関数を呼び出すためのコードを示します。
// migration-lwt.cpp
// compile with: /EHsc
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <concrt.h>
using namespace concurrency;
#define BUF_SIZE 255
void __cdecl MyThreadFunction(LPVOID param);
// Data structure for threads to use.
typedef struct MyData {
int val1;
int val2;
event signal;
} MYDATA, *PMYDATA;
int _tmain()
{
// Allocate memory for thread data.
PMYDATA pData = (PMYDATA) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(MYDATA));
if( pData == NULL )
{
ExitProcess(2);
}
// Set the values of the thread data.
pData->val1 = 50;
pData->val2 = 100;
// Create the thread to begin execution on its own.
CurrentScheduler::ScheduleTask(MyThreadFunction, pData);
// Wait for the task to finish.
pData->signal.wait();
// Free memory allocation.
HeapFree(GetProcessHeap(), 0, pData);
return 0;
}
void __cdecl MyThreadFunction(LPVOID lpParam)
{
PMYDATA pData = (PMYDATA)lpParam;
// Use thread-safe functions to print the parameter values.
TCHAR msgBuf[BUF_SIZE];
StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"),
pData->val1, pData->val2);
size_t cchStringSize;
StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
DWORD dwChars;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
pData->signal.set();
}