プロセスの同期


ミューテックス

前回は、クリティカルセクションという、スレッド間の同期のとり方を説明しました
実は、同様の概念がプロセスの間にも通用します
例えば、重要なファイルをアプリケーションが同時に読み書きしてはまずいことがあります
データベースなど、複数のアクセスを同時に受けるプログラムが想像できますね

複数のプロセスが、同期をとる方法として考えられるのはミューテックスです
これは、相互排他アクセスの許可という部分で、クリティカルセクションに似ています

ミューテックスの概念は、クリティカルセクションと同じで
ミューテックスオブジェクトの所有権を取得するまで、スレッドを待機させるというものです
ただし、ミューテックスオブジェクトはプロセス間で共有することができるのです

ミューテックスオブジェクトを作成するには CreateMutex() 関数を使います
HANDLE CreateMutex(
	LPSECURITY_ATTRIBUTES lpMutexAttributes,
	BOOL bInitialOwner , LPCTSTR lpName
);
lpMutexAttributes は、セキュリティ属性構造体へのポインタを指定します
NULL を指定すればデフォルトのセキュリティが有効となります

bInitialOwner はミューテックスオブジェクトの初期状態を指定します
TRUE を指定すれば、呼び出しスレッドが即座にミューテックスオブジェクトの所有権を得ます
複数のプロセス同期に使う場合、必ず FALSE を指定します

lpName は、MAX_PATH 以内の文字数で、ミューテックスの名前を指定します
既存のイベント、セマフォ、ファイルマッピングオブジェクトと同じ名前を使ってはいけません
イベント、セマフォ、ファイルマッピングオブジェクトなどについては、後記します
名前が必要無い場合は NULL を指定します

関数が成功すれば、ミューテックスオブジェクトのハンドルが、そうでなければ 0 が返ります
ミューテックスオブジェクトが不用になれば CloseHandle() 関数で破棄できます
ただし、プロセスが終了すれば、ミューテックスオブジェクトも破棄されます

ミューテックスの名前は、異なるプロセス間で同じオブジェクトを共有する時に使います
ミューテックスオブジェクトの名前は、全てのプロセスが同じ名前空間を持っています
スレッドは、OpenMutex() 関数を使って、ミューテックスオブジェクトを取得できます
HANDLE OpenMutex(
	DWORD dwDesiredAccess , BOOL bInheritHandle,
	LPCTSTR lpName
);
dwDesiredAccess には、ミューテックスオブジェクトに対するアクセス要求を指定します
Win9x では、常に全てのアクセスフラグを有効にする MUTEX_ALL_ACCESS を指定します
NT では、これに加え、待機関数での使用を許可する SYNCHRONIZE も使えます
待機関数とは、条件が達成されるまでスレッドを待機させる関数群を指します

bInheritHandle は、このハンドルを子プロセスが継承できるかどうかを指定します
TRUE を指定すると、継承できますが、FALSE を指定すると、ハンドルは継承できません
この引数は、プロセスが異なるプロセスを生成した時に意味をなします
プロセスの生成は後ほど説明します。

lpName は、ミューテックスオブジェクトの名前を指定します
成功すればミューテックスオブジェクトのハンドルが、失敗すれば 0 が返ります

つまり、他のスレッド、または他のプロセスが CreateMutex() を使って作成した
ミューテックスオブジェトを、この関数を使っていつでも引き出せるのです
CreateMutex() は、同名のミューテックスオブジェクトが指定されれば
既存のミューテックスのハンドルを返します
同名のミューテックスオブジェクトが複数作成される心配はありません

さて、このミューテックスオブジェクトを使って同期をとるには
待機関数と呼ばれる、スレッドを待機させる関数を使います
代表的なのは WaitForSingleObject() 関数でしょう

DWORD WaitForSingleObject(HANDLE hHandle , DWORD dwMilliseconds);

nHandle には、同期対象となるオブジェクトを指定します
WIndows NT 系の場合は SYNCHRONIZE アクセスをもつオブジェクトでなければなりません
ここに指定できるオブジェクトは、次のものがあります

オブジェクト解説
変更通知 このハンドルは、FindFirstChangeNotification() 関数が返します
変更通知オブジェクトは、指定したディレクトリまたはディレクトリツリーの中で
指定した種類の変更が発生したときに、シグナル状態になります
コンソール入力 このハンドルは、CreateFile() 関数 (CONIN$ 指定) またはGetStdHandle() 関数が返します
このオブジェクトは、コンソールの入力バッファ内に
読み取られていない入力が残っているときはシグナル状態になり
入力バッファが空のときは非シグナル状態になります
イベント このハンドルは、CreateEvent() 関数または OpenEvent() 関数が返します
イベントオブジェクトは、SetEvent() 関数
または PulseEvent() 関数呼び出しによってシグナル状態になります
手動リセットイベントオブジェクトは、ResetEvent() 関数を使って
明示的に非シグナル状態に再設定しなければなりません
自動リセットイベントオブジェクトは、待機関数が制御を返す前に
自動的に非シグナル状態になります
イベントオブジェクトは、非同期操作でも使われます
この場合は、システムがオブジェクトの状態を設定します
ミューテックス このハンドルは、CreateMutex() 関数または OpenMutex() 関数が返します
ミューテックスオブジェクトは、スレッドに所有されているときは非シグナル状態に
スレッドに所有されていないときはシグナル状態になります
待機関数は所有権を要求し、所有権が与えられた時点で
その状態を非シグナル状態に変更します
プロセス このハンドルは、CreateProcess() 関数または OpenProcess() 関数が返します
プロセスオブジェクトは、プロセスが終了するとシグナル状態になります
セマフォ このハンドルは、CreateSemaphore() 関数または OpenSemaphore() 関数が返します
セマフォオブジェクトは、カウントが 0 よりも大きいときにシグナル状態になり
カウントが 0 のときに非シグナル状態になります
現在の状態がシグナル状態の場合、待機関数はカウントを 1 つ減らします
スレッド このハンドルは、CreateProcess() 関数、CreateThread() 関数
CreateRemoteThread() 関数が返します
スレッドオブジェクトは、スレッドが終了するとシグナル状態になります
タイマー タイマーのハンドルは、CreateWaitableTimer() 関数かOpenWaitableTimer() 関数が返します
SetWaitableTimer 関数を呼び出してタイマーをアクティブ化します
アクティブなタイマーが時間切れになると、シグナル状態になります
CancelWaitableTimer() 関数を呼び出すと、タイマーは非アクティブ化します

オブジェクトには、シグナル状態非シグナル状態があり
WaitForSingleObject() 関数は、指定オブジェクトがシグナル状態になれば、制御を返します

解説を読めばわかりますが、ミューテックスもオブジェクトの一つであり
ミューテックスオブジェクトは、所有権が何らかのスレッドに保有されている時は非シグナルです
そして、待機関数にミューテックスオブジェクトを与えると、待機関数は所有権を要求します
待機関数を呼び出したスレッドが所有権を得ることができれば、シグナル状態になります

dwTimeoutInterval は、待機する時間をミリ秒単位で指定します
INFINITE を指定すれば、オブジェクトがシグナル状態になるまで待機します
0 を指定すれば、オブジェクトの状態を調べてすぐに制御を返します

この関数の戻り値は、次のいずれかになります

定数解説
WAIT_ABANDONED 指定されたオブジェクトは
放棄されたミューテックスオブジェクトでした
(あるスレッドが所有権を持っていましたが
そのスレッドは所有権を解放しないで終了しました)
この関数の呼び出しにより、ミューテックスの所有権は呼び出し側スレッドに移り
状態は非シグナル状態になりました
WAIT_OBJECT_0 指定したオブジェクトがシグナル状態になったので
制御を返しました
WAIT_TIMEOUT タイムアウト時間が経過したので、制御を返しました
指定されたオブジェクトは非シグナル状態のままです
WAIT_FAILED 関数は失敗しました

さて、WaitForSingleObject() でミューテックスの所有権を得たならば
その後、スレッドは目的の処理を遂行するでしょう
同期をとるべき処理範囲を抜けたならば、ミューテックスの所有権を解放する必要があります
そうしなければ、他のスレッドがミューテックスの所有権を得られません
ミューテックスオブジェクトの所有権の解放には ReleaseMutex() を使います

BOOL ReleaseMutex(HANDLE hMutex);

hMutex にはミューテックスオブジェクトのハンドルを指定します
関数が成功すれば 0 以外、失敗すれば 0 が返ります
#include <windows.h>

#define MUTEX TEXT("KITTU_MUTEX")

DWORD WINAPI ThreadFunc(LPVOID hWnd) {
	HDC hdc;
	TCHAR str[32];
	int iCount;
	HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS , FALSE , MUTEX);

	SetWindowText(hWnd , TEXT("ミューテックスの解放を待っています"));
	WaitForSingleObject(hMutex , INFINITE);
	SetWindowText(hWnd , TEXT("処理中です..."));

	for (iCount = 0 ; iCount < 1000 ; iCount++) {
		hdc = GetDC(hWnd);
		wsprintf(str , TEXT("Count = %d") , iCount);
		TextOut(hdc , 0 , 0 , str , lstrlen(str));
		Sleep(10);
		ReleaseDC(hWnd , hdc);
	}
	SetWindowText(hWnd , TEXT("ミューテックスを解放しました"));

	ReleaseMutex(hMutex);
	CloseHandle(hMutex);
	ExitThread(TRUE);
}

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	DWORD dwParam;
	static HANDLE hMutex;

	switch (msg) {
	case WM_DESTROY:
		if (hMutex) CloseHandle(hMutex);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hMutex = CreateMutex(NULL , FALSE , MUTEX);
		CreateThread(
			NULL , 0 , ThreadFunc , hWnd , 0 , &dwParam);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style 		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return 1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			200 , 100 , NULL , NULL , hInstance , NULL
	);

	if (hWnd == NULL) return 1;

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}


上の図は、上のプログラムを3つ同時に起動させた時のものです
それぞれは異なるプロセスですが、しっかりと同期がとれていることが確認できます
他のスレッドがミューテックスオブジェクトを所有している時、他のスレッドは待機しています
ミューテックスオブジェクトを所有すれば、スレッドは 0 〜 1000 までのカウントを表示ます
そして、カウントが終了すればミューテックスの所有権を解放して次のウィンドウが処理に入ります


セマフォ

クリティカルセクションやミューテックスを使えば
特定の処理は確実に一つのスレッドだけが実行するように仕掛けられました
これで、ファイルの同時アクセスなどを避けることができるようになるでしょう

ところで、もし同時に3つのスレッドまでは処理しても良い場合があればどうでしょうか?
ミューテックスなどを使って1ずつ逐次にやらせるのは時間の無駄です
このような、実行するスレッドの数を制限したい場合、ミューテックスは適切ではありません

そのような場合は セマフォ を使います
セマフォの特徴は、同期にカウンタを用いるというところにあります
セマフォは、カウンタが 0 以上であればシグナル状態、 0 であれば非シグナル状態となります

例えば、3つのスレッドまでの実行を許可する待機関数を実現するには
セマフォのカウンタの初期値を3にし、スレッドごとに1減算するようにします
そうすれば、スレッドが 3 つ実行されている場合、カウンタが 0 の非シグナル状態になります
処理が終了すれば、スレッドはカウンタを 1 インクリメントし、次のスレッドが実行されます

セマフォオブジェクトを作成するには CreateSemaphore() 関数を使います
基本的な考え方は、ミューテックスと同じです
HANDLE CreateSemaphore(
	LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
	LONG lInitialCount , LONG lMaximumCount,
	LPCTSTR lpName
);
lpSemaphoreAttributes には、セキュリティ属性構造体へのポインタを指定します
lIniticalCount はセマフォカウンタの初期値を
lMaximumCount はセマフォカウンタの最大値を指定します
lpName には、生成するセマフォオブジェクトの名前を指定します

関数が成功すればセマフォオブジェクトのハンドル、失敗すれば 0 が返ります
セマフォオブジェクトの名前は、他のオブジェクトの名前と同じ名前を指定してはいけません

セマフォオブジェクトを名前から取得するには OpenSemaphore() を使います
これは、ミューテックスで言う OpenMutex() 関数にあたるものです
HANDLE OpenSemaphore(
	DWORD dwDesiredAccess ,
	BOOL bInheritHandle ,
	LPCTSTR lpName
);
dwDesiredAccess にはセマフォオブジェクトに対するアクセス要求を指定します
この引数には、次の定数を指定することができます

定数解説
SEMAPHORE_ALL_ACCESS セマフォオブジェクトに対して可能なすべてのアクセスを要求します
SEMAPHORE_MODIFY_STATE ReleaseSemaphore() 関数によるカウント値の修正を要求します
SYNCHRONIZE Windows NT:
待機関数での使用を要求します

bInheritHandle は、返されるハンドルを継承可能にするかどうかを指定します
TRUE を指定すると、継承できますが、FALSE を指定すると、ハンドルは継承できません
lpName には、セマファオブジェクトの名前を指定します
成功すればセマフォオブジェクトのハンドル、失敗すれば NULL が返ります

セマフォオブジェクトを解放するには ReleaseSemaphore() を使います
この関数は、セマフォカウンタをいくつ増やすかを指定することで解放します
BOOL ReleaseSemaphore(
	HANDLE hSemaphore,
	LONG lReleaseCount,
	LPLONG lpPreviousCount
);
hSemaphore には、対象のセマフォオブジェクトを指定します
lReleaseCount は、カウント値の増分を指定します
ただし、セマフォオブジェクトの最大カウント数を超えた場合は失敗します

lpPreviousCount は、変更する前のカウント値を格納する LONG 型へのポインタを指定します
不必要な場合は、NULL を指定することができます
関数が成功すれば 0 以外、失敗すれば 0 が返ります
#include <windows.h>

#define SEMAPHORE TEXT("KITTU_SEMAPHORE")

DWORD WINAPI ThreadFunc(LPVOID hWnd) {
	HDC hdc;
	TCHAR str[32];
	int iCount;
	HANDLE hSemaphore = OpenSemaphore(
		SEMAPHORE_ALL_ACCESS , FALSE , SEMAPHORE);

	SetWindowText(hWnd , TEXT("順番を待っています"));
	WaitForSingleObject(hSemaphore , INFINITE);
	SetWindowText(hWnd , TEXT("処理中です..."));

	for (iCount = 0 ; iCount < 1000 ; iCount++) {
		hdc = GetDC(hWnd);
		wsprintf(str , TEXT("Count = %d") , iCount);
		TextOut(hdc , 0 , 0 , str , lstrlen(str));
		Sleep(10);
		ReleaseDC(hWnd , hdc);
	}
	SetWindowText(hWnd , TEXT("処理を終了しました"));

	ReleaseSemaphore(hSemaphore , 1 , NULL);
	CloseHandle(hSemaphore);
	ExitThread(TRUE);
}

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	DWORD dwParam;
	static HANDLE hSemaphore;

	switch (msg) {
	case WM_DESTROY:
		if (hSemaphore) CloseHandle(hSemaphore);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hSemaphore = CreateSemaphore(NULL , 2 , 2 , SEMAPHORE);
		CreateThread(
			NULL , 0 , ThreadFunc , hWnd , 0 , &dwParam);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style 		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return 1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			200 , 100 , NULL , NULL , hInstance , NULL
	);

	if (hWnd == NULL) return 1;

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}
このプログラムは、ミューテックスのプログラムをセマフォに改良したのです
ミューテックスの時とは異なり、このプログラムは2つまで同時にカウントすることができます
3つ以上、このプログラムを起動すると、カウンタが 0 なので待機状態になります


イベント

これまでの同期方法は、プログラム自体が制御するようなものではなく
プログラムの状態、流れによって同期をとるものでした

Windows は「イベント駆動」型のシステムです
場合によっては、何らかのイベントによってスレッドを制御したいと思うかもしれません
つまり、スレッドの待機関数が制御を返すタイミングをプログラムが指定するということです
これを実現する同期方法がイベントと呼ばれる方法です

イベントオブジェクトは、関数によって直接シグナル、非シグナル状態を操作できます
イベントオブジェクトを作成するには CreateEvent() 関数を使います
HANDLE CreateEvent(
	LPSECURITY_ATTRIBUTES lpEventAttributes ,
	BOOL bManualReset , BOOL bInitialState ,
	LPCTSTR lpName
);
lpEventAttributes は、セキュリティ属性構造体へのポインタを指定します

bManualReset は、手動リセットイベントにするかどうかをブーリアンで指定します
TRUE をすると手動、FALSE にするとリセットイベントは自動になります
自動にした場合、待機関数が制御を返すと、自動的にオブジェクトが非シグナルになります

bInitialState にはイベントオブジェクトの初期状態を指定します
TRUE を指定するとシグナル状態、FALSE なら非シグナル状態を表します
lpName には、イベントオブジェクトの名前を指定します
成功すればイベントオブジェクトのハンドルが、そうでなければ NULL が返ります

名前付きのイベントオブジェクトを取得するには OpenEvent() を使います
OpenMutex() や OpenSemaphore() 関数と同じような関数です
HANDLE OpenEvent(
	DWORD dwDesiredAccess ,
	BOOL bInheritHandle ,
	LPCTSTR lpName
);
dwDesiredAccess にはイベントオブジェクトに対して要求するアクセスの種類を指定します
この引数には、次の定数のいずれかを指定できます

定数解説
EVENT_ALL_ACCESS イベントオブジェクトに対して可能なアクセスすべて
EVENT_MODIFY_STATE SetEvent関数とResetEvent関数によるイベントの状態の変更
SYNCHRONIZE Windows NT:
待機関数によるイベントのシグナル化待ち

bInheritHandle には、取得したハンドルの継承を許可するかどうかを指定します
TRUE を指定すると、継承できますが、FALSE を指定すると、ハンドルは継承できません
lpName には、イベントオブジェクトの名前を指定します
関数が成功すればイベントオブジェクトのハンドル、失敗すれば NULL が返ります

イベントオブジェクトをシグナル状態にするには SetEvent() 関数を
非シグナル状態にするには ResetEvent() 関数を使います

BOOL SetEvent(HANDLE hEvent);
BOOL ResetEvent(HANDLE hEvent);

hEvent には、対象のイベントオブジェクトを指定します
関数が成功すると 0 以外、失敗すると 0 が返ります
#include <windows.h>

#define EVENT TEXT("KITTU_EVENT")

DWORD WINAPI ThreadFunc(LPVOID hWnd) {
	HDC hdc;
	TCHAR str[32];
	int iCount;
	HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS , FALSE , EVENT);

	SetWindowText(hWnd , TEXT("待機しています"));
	WaitForSingleObject(hEvent , INFINITE);
	ResetEvent(hEvent);
	SetWindowText(hWnd , TEXT("処理中です..."));

	for (iCount = 0 ; iCount < 1000 ; iCount++) {
		hdc = GetDC(hWnd);
		wsprintf(str , TEXT("Count = %d") , iCount);
		TextOut(hdc , 0 , 0 , str , lstrlen(str));
		Sleep(10);
		ReleaseDC(hWnd , hdc);
	}
	SetWindowText(hWnd , TEXT("処理を終了しました"));
	CloseHandle(hEvent);
	ExitThread(TRUE);
}

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	DWORD dwParam;
	static HANDLE hEvent;

	switch (msg) {
	case WM_DESTROY:
		if (hEvent) CloseHandle(hEvent);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		hEvent = CreateEvent(NULL , TRUE , FALSE , EVENT);
		CreateThread(
			NULL , 0 , ThreadFunc , hWnd , 0 , &dwParam);
		return 0;
	case WM_LBUTTONUP:
		SetEvent(hEvent);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style 		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return 1;

	hWnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			200 , 100 , NULL , NULL , hInstance , NULL
	);

	if (hWnd == NULL) return 1;

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}
このプログラムを実行すると、まずスレッドが生成されます
しかし、スレッドは即座に待機関数で、イベントオブジェクトがシグナル状態になるのを待ちます
ウィンドウのクライアント領域をクリックすれば、イベントオブジェクトはシグナル状態になります

当然、異なるプロセス間の同期にも、そのまま使うことができます
このプログラムを同時に複数実行して試してみればわかるでしょう


CreateMutex()

HANDLE CreateMutex(
	LPSECURITY_ATTRIBUTES lpMutexAttributes,
	BOOL bInitialOwner , LPCTSTR lpName
);
ミューテックスオブジェクトを作成します

lpMutexAttributes - セキュリティ属性構造体へのポインタを指定します
bInitialOwner - TRUE なら呼び出しスレッドにオブジェクトの所有権が与えられます
lpName - MAX_PATH 以内の文字数で、ミューテックスの名前を指定します

戻り値 - ミューテックスオブジェクトのハンドル、そうでなければ 0

OpenMutex()

HANDLE OpenMutex(
	DWORD dwDesiredAccess , BOOL bInheritHandle,
	LPCTSTR lpName
);
作成済みのミューテックスオブジェクトを開きます

dwDesiredAccess - ミューテックスオブジェクトに対するアクセス要求を指定します
bInheritHandle - TRUE ならばハンドルを継承できますが、FALSE ならばできません
lpName - ミューテックスオブジェクトの名前を指定します

戻り値 - ミューテックスオブジェクトのハンドル、失敗すれば 0

dwDesiredAccess には、次の定数のいずれかを指定します

定数解説
MUTEX_ALL_ACCESS ミューテックスオブジェクトに対して可能なすべてのアクセスを要求します
SYNCHRONIZE Windows NT:
待機関数や ReleaseMutex 関数でのミューテックスハンドルの使用を要求します

WaitForSingleObject()

DWORD WaitForSingleObject(HANDLE hHandle , DWORD dwMilliseconds);

オブジェクトがシグナル状態になる
またはタイム合うとが経過するまでスレッドを待機させます

nHandle - 同期対象となるオブジェクトを指定します
dwTimeoutInterva - 待機する時間をミリ秒単位で指定します

戻り値 - オブジェクトの状態を表すフラグ

この関数の戻り値は、次のいずれかになります

定数解説
WAIT_ABANDONED 指定されたオブジェクトは
放棄されたミューテックスオブジェクトでした
(あるスレッドが所有権を持っていましたが
そのスレッドは所有権を解放しないで終了しました)
この関数の呼び出しにより、ミューテックスの所有権は呼び出し側スレッドに移り
状態は非シグナル状態になりました
WAIT_OBJECT_0 指定したオブジェクトがシグナル状態になったので
制御を返しました
WAIT_TIMEOUT タイムアウト時間が経過したので、制御を返しました
指定されたオブジェクトは非シグナル状態のままです
WAIT_FAILED 関数は失敗しました

ReleaseMutex()

BOOL ReleaseMutex(HANDLE hMutex);

ミューテックスオブジェクトの所有権を解放し、シグナル状態にします

hMutex - ミューテックスオブジェクトのハンドルを指定します

戻り値 - 成功すれば 0 以外、失敗すれば 0

CreateSemaphore()

HANDLE CreateSemaphore(
	LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
	LONG lInitialCount , LONG lMaximumCount,
	LPCTSTR lpName
);
セマフォオブジェクトを作成します

lpSemaphoreAttributes - セキュリティ属性構造体へのポインタを指定します
lIniticalCount - セマフォカウンタの初期値を指定します
lMaximumCount - セマフォカウンタの最大値を指定します
lpName - 生成するセマフォオブジェクトの名前を指定します

戻り値 - セマフォオブジェクトのハンドル、失敗すれば 0

OpenSemaphore()

HANDLE OpenSemaphore(
	DWORD dwDesiredAccess ,
	BOOL bInheritHandle ,
	LPCTSTR lpName
);
作成済みのセマフォオブジェクトを開きます

dwDesiredAccess - セマフォオブジェクトに対するアクセス要求を指定します
bInheritHandle - TRUE ならばハンドルを継承できますが、FALSE ならばできません
lpName - セマファオブジェクトの名前を指定します

戻り値 - セマフォオブジェクトのハンドル、失敗すれば NULL

dwDesiredAccess には、次の定数のいずれかを指定します

定数解説
SEMAPHORE_ALL_ACCESS セマフォオブジェクトに対して可能なすべてのアクセスを要求します
SEMAPHORE_MODIFY_STATE ReleaseSemaphore() 関数によるカウント値の修正を要求します
SYNCHRONIZE Windows NT:
待機関数での使用を要求します

ReleaseSemaphore()

BOOL ReleaseSemaphore(
	HANDLE hSemaphore,
	LONG lReleaseCount,
	LPLONG lpPreviousCount
);
セマフォオブジェクトのカウンタをし定数だけ増やします

hSemaphore - 対象のセマフォオブジェクトを指定します
lReleaseCount - カウント値の増分を指定します
lpPreviousCount - 変更前のカウント値を格納する LONG 型のポインタを指定します

戻り値 - 成功すれば 0 以外、失敗すれば 0 が返ります

CreateEvent()

HANDLE CreateEvent(
	LPSECURITY_ATTRIBUTES lpEventAttributes ,
	BOOL bManualReset , BOOL bInitialState ,
	LPCTSTR lpName
);
イベントオブジェクトを作成します

lpEventAttributes - セキュリティ属性構造体へのポインタを指定します
bManualReset - TRUE なら手動、FALSE なら自動のリセットイベントになります
bInitialState - TRUE ならシグナル状態、FALSE なら非シグナル状態を初期値とします
lpName - イベントオブジェクトの名前を指定します

戻り値 - イベントオブジェクトのハンドル、そうでなければ NULL

OpenEvent()

HANDLE OpenEvent(
	DWORD dwDesiredAccess ,
	BOOL bInheritHandle ,
	LPCTSTR lpName
);
作成済みのイベントオブジェクトを開きます

dwDesiredAccess - 要求するアクセスの種類を指定します
bInheritHandle - TRUE ならばハンドルを継承できますが、FALSE ならばできません
lpName - イベントオブジェクトの名前を指定します

戻り値 - イベントオブジェクトのハンドル、失敗すれば NULL

dwDesiredAccess には、次の定数のいずれかを指定します

定数解説
EVENT_ALL_ACCESS イベントオブジェクトに対して可能なアクセスすべて
EVENT_MODIFY_STATE SetEvent関数とResetEvent関数によるイベントの状態の変更
SYNCHRONIZE Windows NT:
待機関数によるイベントのシグナル化待ち

SetEvent()

BOOL SetEvent(HANDLE hEvent);

イベントオブジェクトをシグナル状態にします

hEvent - 対象のイベントオブジェクトを指定します

戻り値 - 成功すると 0 以外、失敗すると 0

ResetEvent()

BOOL ResetEvent(HANDLE hEvent);

イベントオブジェクトを非シグナル状態にします

hEvent - 対象のイベントオブジェクトを指定します

戻り値 - 成功すると 0 以外、失敗すると 0



前のページへ戻る次のページへ