セマフォはちょっと説明が難しいです。
セマフォは、現在値を持ちます。これが0以外であれば、Waitナンタラ関数 は直ちに帰ります。この時セマフォの値は1減ります。
セマフォが0になった時、Waitナンタラ関数は0より大になるまで待機します。
ロックを解放するにはReleaseSemaphore関数を使います。これにより、セマフォの値 は1増えます。
セマフォを作成するにはCreateSemaphore関数を使います。
HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // セキュリティ記述子 LONG lInitialCount, // 初期カウント LONG lMaximumCount, // 最大カウント LPCTSTR lpName // オブジェクト名 );lpSemaphoreAttributesには、セキュリティ記述子を指定します。 NULLを指定するとデフォルトのセキュリティとなります。
lInitialCountには、初期のセマフォのカウントを指定します。
lMaximumCountには、カウントの最大値を指定します。
lpNameには、セマフォの名前を指定します。
戻り値はセマフォのハンドルです。関数が失敗した時はNULLが返ります。
プロセスが終了する時、プロセスが所有していたハンドルを自動的に閉じます。 明示的に閉じる時はCloseHandle関数を使います。
セマフォのカウントを増やすにはReleaseSemaphore関数を使います。
BOOL ReleaseSemaphore( HANDLE hSemaphore, // セマフォのハンドル LONG lReleaseCount, // カウントを増やすべき数 LPLONG lpPreviousCount // それまでのカウント );hSemaphoreには、セマフォのハンドルを指定します。
lReleaseCountには、カウントをいくつ増やすかを指定します。0より大きい数を指定します。
lpPreviousCountには、それまでのカウントを取得する変数のポインタを指定します。 不要であれば、NULLを指定できます。
関数が成功すると0以外が、失敗すると0が返ります。
さて、セマフォの最大カウントを1にすると、ミューテックスと同じ動作になります。 これをバイナリセマフォと呼ぶことがあります。
サンプルでは、最大カウントを1にして前章と同じサンプルを書き直してみます。
/* mult08.c */ #define SEMAPHORENAME "MYSEMAPHORE" #include <stdio.h> #include <conio.h> #include <windows.h> #include <process.h> unsigned __stdcall mythread0(LPVOID); unsigned __stdcall mythread1(LPVOID); HANDLE hEvent[2]; BOOL bThEnd = FALSE; int i; int main() { int i; HANDLE hTh[2]; DWORD thID[2]; HANDLE hSemaphore; hSemaphore = CreateSemaphore(NULL, 1, 1, SEMAPHORENAME); if (hSemaphore == NULL) { printf("セマフォ作成失敗\n"); return -1; } hEvent[0] = CreateEvent(NULL, TRUE, FALSE, "CH0"); hEvent[1] = CreateEvent(NULL, TRUE, FALSE, "CH1"); hTh[0] = (HANDLE)_beginthreadex( NULL, 0, mythread0, &hSemaphore, CREATE_SUSPENDED, &thID[0] ); if (hTh[0] == NULL) { printf("スレッド0作成失敗\n"); return -1; } hTh[1] = (HANDLE)_beginthreadex( NULL, 0, mythread1, &hSemaphore, CREATE_SUSPENDED, &thID[1] ); if (hTh[1] == NULL) { printf("スレッド1作成失敗\n"); return -1; } //各スレッド実行開始 for (i = 0; i < 2; i++) ResumeThread(hTh[i]); _getch(); bThEnd = TRUE; WaitForMultipleObjects(2, hEvent, TRUE, INFINITE); for (i = 0; i < 2; i++) { if (CloseHandle(hTh[i])) { printf("hTh[%d]のクローズに成功\n", i); } else { printf("hTh[%d]のクローズ失敗\n", i); } } if (CloseHandle(hSemaphore)) { printf("セマフォハンドルのクローズに成功\n"); } else { printf("セマフォハンドルのクローズに失敗\n"); } printf("親を終了します\n"); return 0; } unsigned __stdcall mythread0(LPVOID lpx) { HANDLE hS; LONG lPrevious; hS = *(HANDLE *)lpx; while (!bThEnd) { WaitForSingleObject(hS, INFINITE); printf("スレッド0が%dを表示\n", i++); ReleaseSemaphore(hS, 1, &lPrevious); } WaitForSingleObject(hS, INFINITE); printf("スレッド0終了\n"); ReleaseSemaphore(hS, 1, &lPrevious); SetEvent(hEvent[0]); return 0; } unsigned __stdcall mythread1(LPVOID lpx) { HANDLE hS; LONG lPrevious; hS = *(HANDLE *)lpx; while (!bThEnd) { WaitForSingleObject(hS, INFINITE); printf("スレッド1が%dを表示\n", i++); ReleaseSemaphore(hS, 1, &lPrevious); } WaitForSingleObject(hS, INFINITE); printf("スレッド1終了\n"); ReleaseSemaphore(hS, 1, &lPrevious); SetEvent(hEvent[1]); return 0; }これが、前章と同じ動作をするか確認してみてください。
Update Dec/04/2004 By Y.Kumei