第104章 マルチスレッド その6


今回はミューテックスについてやります。

これは、クリティカルセクションと似ています。 クリティカルセクションはそのプロセスでしか利用できませんが、ミューテックスは複数のプロセスで利用できます。

複数のプロセスで利用する場合は、ミューテックスの名前を付ける必要があります。

一つのプロセスのみで利用する場合は、名前は付けなくてもかまいません。 ミューテックスは、ただ一つのスレッドのみが所有できます。 所有権を放棄するまで他のスレッドは、これを所有できません。


ミューテックスを作成するにはCreateMutex関数を使います。

HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,  // セキュリティ記述子
  BOOL bInitialOwner,                       // 最初の所有者
  LPCTSTR lpName                            // オブジェクトの名前
);
lpMutexAttributesには、セキュリティ属性を指定します。NULLだとデフォルトの セキュリティとなります。

bInitialOwnerには、この関数を呼び出したスレッドが最初の所有者になるか どうかを指定します。TRUEなら所有者となり、FALSEならなりません。

lpNameには、名前を指定します。

成功するとミューテックスのハンドルが返ります。
同じ名前のミューテックスがすでに存在しても、失敗にはなりません。

関数が失敗するとNULLが返されます。

ミューテックスが不要になったら必ずCloseHandleします。

スレッドがミューテックスを所有するには、ミューテックスのハンドルを指定して 待機関数を呼び出します。

所有権を放棄するには、ReleaseMutex関数を呼び出します。

BOOL ReleaseMutex(
  HANDLE hMutex   // ミューテックスオブジェクトのハンドル
);
成功すると0以外の数値が、失敗すると0が返されます。

では、サンプルを見てみましょう。

2つの子スレッドが、グローバル変数iを見て、これを表示します。 そして、iの数字を1つ増やします。

これをbThEndがTRUEになるまで延々と繰り返します。

ユーザーが何かキーを押すと、bThEndがTRUEになり、各スレッドに 終了を告げます。

/* mult07.c */

#define MUTEXNAME "MYMUTEX"
#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 hMutex;

    hMutex = CreateMutex(NULL, FALSE, MUTEXNAME);
    if (hMutex == 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,
        &hMutex,
        CREATE_SUSPENDED,
        &thID[0]
    );
    if (hTh[0] == NULL) {
        printf("スレッド0作成失敗\n");
        return -1;
    }

    hTh[1] = (HANDLE)_beginthreadex(
        NULL,
        0,
        mythread1,
        &hMutex,
        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(hMutex)) {
        printf("ミューテックスハンドルのクローズに成功\n");
    } else {
        printf("ミューテックスハンドルのクローズに失敗\n");
    }
    printf("親を終了します\n");
    return 0;
}
main関数では、bThEndをTRUEにした後、WaitForMultipleObjects関数で 2つのイベントがシグナル状態になるのを待ちます。

各スレッドは、ループを抜けた時に、イベントをシグナル状態にします。

2つのスレッドがループを抜けて終了するのを待っているわけです。

unsigned __stdcall mythread0(LPVOID lpx)
{
    HANDLE hM;

    hM = *(HANDLE *)lpx;

    while (!bThEnd) {
        WaitForSingleObject(hM, INFINITE);
        printf("スレッド0が%dを表示\n", i++);
        ReleaseMutex(hM);
    }
    WaitForSingleObject(hM, INFINITE);
    printf("スレッド0終了\n");
    ReleaseMutex(hM);
    SetEvent(hEvent[0]);                                \
    return 0;
}
第一引数で、ミューテックスハンドルをもらいます。

bThEndがTRUEになるまで、以下のことを繰り返します。

WaitForSingleObject関数でミューテックスの所有権を取得します。

グローバル変数のiを表示して、1増やします。

ミューテックスの所有権を放棄します。

bThEndがTRUEになってループを抜けた後、 また、WaitForSingleObject関数で、ミューテックスの所有権を取得します。

そして、スレッドが終了することを表示します。

表示が終わったらミューテックスの所有権を放棄します。

ループを抜けた後、ミューテックスの所有は必要ないように思われるかもしれませんが これをしないとおかしなことが起ります。

「スレッド0終了」と表示している最中に、もう一つのスレッドが表示を開始したり あるいは「スレッド0終了」が2回表示されたりします。

さて、終了の表示が終わったら、イベントをシグナル状態にします。

unsigned __stdcall mythread1(LPVOID lpx)
{
    HANDLE hM;

    hM = *(HANDLE *)lpx;

    while (!bThEnd) {
        WaitForSingleObject(hM, INFINITE);
        printf("スレッド1が%dを表示\n", i++);
        ReleaseMutex(hM);
    }
    WaitForSingleObject(hM, INFINITE);
    printf("スレッド1終了\n");
    ReleaseMutex(hM);
    SetEvent(hEvent[1]);
    return 0;

}
mythread0関数とほぼ同じ内容ですが、最後にhEvent[1]をシグナル状態にするところが 違います。

では、実行結果を見てみましょう。




[Index][総合Index] [Previous Chapter] [Next Chapter]

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