第105章 マルチスレッド その7


今回は、セマフォについてやります。


セマフォはちょっと説明が難しいです。

セマフォは、現在値を持ちます。これが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;

}
これが、前章と同じ動作をするか確認してみてください。
[Index][総合Index] [Previous Chapter] [Next Chapter]

Update Dec/04/2004 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。