マルチスレッドとイベント マイナーすぎる3DS備忘録

3DSでマルチスレッディングを行う際に使用するEventについて書いていきます。



イベントの作成

Result svcCreateEvent(Handle* event, ResetType reset_type);

引数にポインタを渡して作成したイベントのハンドルを取得しましょう。ResetTypeについてはこちらをご覧ください。



イベントを待つ

Result svcWaitSynchronization(Handle handle, s64 nanoseconds);

handleには作成したイベントのハンドルを渡しましょう。nanosecondはタイムアウトです。タイムアウトした場合、0x09401BFEが返ってきます。



シグナルの送信

Result svcSignalEvent(Handle handle);

handleはお察しの通りイベントのハンドルです。イベントにシグナルします。



イベントのクリア

Result svcClearEvent(Handle handle);

handleはイベントのハンドルです。ResetTypeをRESET_STICKYにした場合に使用します。RESET_STICKYだとイベントをクリアしないとシグナルがずっと送信されたままになります。クリアするともう一度イベントを待つことができます。




#include <stdio.h>
#include <3ds.h>

// イベントのハンドル
Handle eventHandle;

// スレッドのフラグ
bool runThread = true;

void threadMain(void *arg) {
    while(runThread) {
        // イベントを待つ
        svcWaitSynchronization(eventHandle, U64_MAX);

        printf("Hello World!\n");
    }
}

int main(void)
{
    // 画面を初期化
    gfxInitDefault();
    consoleInit(GFX_TOP, NULL);

    // イベントを作成
    svcCreateEvent(&eventHandle, RESET_ONESHOT);

    // スレッドを作成
    Thread threadHandle = threadCreate(threadMain, 0, 0x1000, 0x3f, -2, true);

    while (aptMainLoop())
    {
        // キー入力を更新
        hidScanInput();
        u32 key = hidKeysDown();

        if (key & KEY_START)
            break;

        // Aボタンが押されたら
        if (key & KEY_A)
        {
            // イベントにシグナルを送信
            svcSignalEvent(eventHandle);
        }

        // 画面を更新
        gfxFlushBuffers();
        gfxSwapBuffers();
        gspWaitForVBlank();
    }

    // スレッドのフラグを更新
    runThread = false;

    // スレッドはイベントを待機中なので、シグナルを送りスレッドを動かせる
    svcSignalEvent(eventHandle);

    // スレッドの終了を待つ
    threadJoin(threadHandle, U64_MAX);

    // イベントハンドルを閉じる
    svcCloseHandle(eventHandle);

    gfxExit();
    return 0;
}

Aボタンを押したらシグナルを送信し、待機スレッドはシグナルを検知したらHello World!を出力します。
例にある通り、使わなくなったイベントはsvcCloseHandleでハンドルを閉じましょう。



終わりに
前回よりはわかりやすいと思います。わからないことがあれば気軽にどうぞ!