 前章のサンプルを少し作りかえて、もう少しスレッドの優先順位の差が明白に
なるようにしてみましょう。
前章のサンプルを少し作りかえて、もう少しスレッドの優先順位の差が明白に
なるようにしてみましょう。
/* multiwait.c */
#include <stdio.h>
#include <process.h>
#include <windows.h>
#include <conio.h>
typedef struct _tagDATA{
    BOOL bEnd;
    int n;
} MYDATA;
unsigned __stdcall mythread0(void *);
unsigned __stdcall mythread1(void *);
CRITICAL_SECTION cs;
int main()
{
    HANDLE hTh[2];
    DWORD dwID[2];
    DWORD dwSleep;
    int i;
    static MYDATA mydata;
    mydata.bEnd = FALSE;
    mydata.n = 1000;
    InitializeCriticalSection(&cs);
    hTh[0] = (HANDLE)_beginthreadex(
        NULL,
        0,
        mythread0,
        &mydata,
        CREATE_SUSPENDED,
        &dwID[0]
    );
    hTh[1] = (HANDLE)_beginthreadex(
        NULL,
        0,
        mythread1,
        &mydata,
        CREATE_SUSPENDED,
        &dwID[1]
    );
    SetThreadPriority(hTh[0], THREAD_PRIORITY_HIGHEST);
    SetThreadPriority(hTh[1], THREAD_PRIORITY_LOWEST);
    printf("何ミリセコンド休みますか--");
    scanf("%d", &dwSleep);
    for (i = 0; i < 2; i++)
        ResumeThread(hTh[i]);
    Sleep(dwSleep);
        mydata.bEnd = TRUE;
    WaitForMultipleObjects(2, hTh, TRUE, INFINITE);
    for (i = 0; i < 3; i++)
        CloseHandle(hTh[i]);
    printf("親の終了\n");
    return 0;
}
unsigned __stdcall mythread0(void *lpx)
{
    int i = 0;
    MYDATA *lpdata;
    lpdata = (MYDATA *)lpx;
    while (!lpdata->bEnd) {
        EnterCriticalSection(&cs);
        lpdata->n++;
        LeaveCriticalSection(&cs);
        printf("スレッド0 = %d\n", lpdata->n);
    }
    printf("スレッド0終了\n");
    DeleteCriticalSection(&cs);
    return 0;
}
unsigned __stdcall mythread1(void *lpx)
{
    int i = 0;
    MYDATA *lpdata;
    lpdata = (MYDATA *)lpx;
    while (!lpdata->bEnd) {
        EnterCriticalSection(&cs);
        lpdata->n--;
        LeaveCriticalSection(&cs);
        printf("スレッド1 = %d\n", lpdata->n);
    }
    printf("スレッド1終了\n");
    return 0;
}
最初に
typedef struct _tagDATA{
    BOOL bEnd;
    int n;
} MYDATA;
というように、構造体をtypedefしています。
この構造体を子スレッドに渡します。nには、適当な整数値を指定します。
ある子スレッドは、この値を1ずつ増やします。
別のスレッドは、この値を1ずつ減らします。
この2つのスレッドが同程度に実行されるならnの値は、あまり変わらないはずです。
また、bEndがTRUEになったら、スレッド終了の合図です。
main関数では、まずサスペンド状態で2つの子スレッドを作ります。
そして、それぞれに優先順位の差をつけます。
次に、ユーザーに親スレッドが、何ミリセコンド休むかを尋ねます。
その後、スレッドを一斉に動かします。
Sleep関数で親スレッドは休止します。
指定の時間が経過したら、bEndをTRUEにして子スレッドに終了を伝えます。
WaitForMultipleObjects関数で2つの子スレッドが終了するのを待ちます。
CloseHandleで子スレッドのハンドルをクローズします。
また、このプログラムでは、nを子スレッドが増減するときにクリティカルセクション を利用して排他制御をしています。 そうしないと、変数nが壊れてしまう危険があるからですね。
mythread0子スレッド関数では、nを1ずつ増やします。
mythread1子スレッド関数では、nを1ずつ減らします。
mythread0の方が優先順位が高いので、nの値は次第に増加していくはずです。
どちらのスレッド関数も、bEndの値がTRUEになったらwhileループを抜けて終了します。
では、本当にnは増加していくのか見てみましょう。
 左の図は500ミリ秒親スレッドが休んでいる間に子スレッドが増減した結果です。
明らかに1000より増えていますね。
左の図は500ミリ秒親スレッドが休んでいる間に子スレッドが増減した結果です。
明らかに1000より増えていますね。
スレッドの優先順位を逆にして、nの値が減少していくのか確かめてみてください。
Update May/24/2005 By Y.Kumei