今回は、セマフォについてやります。
セマフォはちょっと説明が難しいです。
セマフォは、現在値を持ちます。これが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