チュートリアル: 既存のコードを改変して軽量タスクを使用する

ここでは、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

コンカレンシー ランタイムを使用して同じタスクを実行するようにこのコード例を改変する手順を次に示します。

軽量タスクを使用するように例を改変するには

  1. ヘッダー ファイル concrt.h の #include ディレクティブを追加します。
#include <concrt.h>
  1. using 名前空間の concurrency ディレクティブを追加します。
using namespace concurrency;
  1. MyThreadFunction の宣言を次のように変更して、__cdecl 呼び出し規約を使用すると共に、void を返します。
void __cdecl MyThreadFunction(LPVOID param);
  1. MyData 構造体を変更して、タスクが完了したことをメイン アプリケーションに通知する concurrency::event オブジェクトを含めます。
typedef struct MyData {
    int val1;
    int val2;
    event signal;
} MYDATA, *PMYDATA;
  1. CreateThread 呼び出しを concurrency::CurrentScheduler::ScheduleTask メソッドの呼び出しで置き換えます。
CurrentScheduler::ScheduleTask(MyThreadFunction, pData);
  1. タスクの完了を待つために、WaitForSingleObject 呼び出しを concurrency::event::wait メソッドの呼び出しで置き換えます。
// Wait for the task to finish.
pData->signal.wait();
  1. CloseHandle 呼び出しを削除します。

  2. 手順 3. に合わせて、MyThreadFunction の定義のシグネチャを変更します。

void __cdecl MyThreadFunction(LPVOID lpParam)
  1. MyThreadFunction 関数の末尾で concurrency::event::set メソッドを呼び出して、タスクが完了したことをメイン アプリケーションに通知します。
pData->signal.set();
  1. 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();
}

関連項目

タスク スケジューラ
Scheduler クラス