スレッドについて

スレッドフレームワーク

CRI Atomライブラリは、ファイル読み込みや音声データ再生処理を、アプリケーションと並列に効率的に実行できるよう、スレッドシステムを使用しています。
CRI Atomライブラリは「スレッドフレームワーク」に従って動作しており、アプリケーションの要求に合わせて、スレッドフレームワークのタイプ「スレッドモデル」を指定することができます。

スレッドモデルには3つのタイプがあります。
ライブラリ初期化用のコンフィグ構造体( CriAtomExConfig )の thread_model メンバーでスレッドモデルを指定します。

スレッドフレームワークの種類
スレッドモデル 説明 初期化定数
マルチスレッドフレームワーク(タイマ駆動式) ライブラリでスレッド作成 CRIATOMEX_THREAD_MODEL_MULTI
マルチスレッドフレームワーク(ユーザ駆動式) ライブラリでスレッド作成 CRIATOMEX_THREAD_MODEL_MULTI_USER_DRIVEN
ユーザマルチスレッドフレームワーク アプリでスレッド作成 CRIATOMEX_THREAD_MODEL_USER_MULTI
シングルスレッドフレームワーク スレッド未使用 CRIATOMEX_THREAD_MODEL_SINGLE


いずれのスレッドモデルでにおいても、フレームワークを正しく動作させるには、「定期的にサーバー処理関数を実行する」ことが重要となります。

マルチスレッドフレームワーク

初期化処理時にマルチスレッドフレームワーク(タイマー駆動式)を選択した場合、ライブラリは内部的にスレッドを作成し、スレッド上で音声データのデコードやファイルアクセスを行います。

デフォルトのCRI Atomスレッド優先度は THREAD_PRIORITY_HIGHEST です。

マルチスレッドフレームワークは、スレッドの駆動方法の違いにより、さらに以下の2タイプに区別されます。
タイマー駆動式について

タイマー駆動時はAtomライブラリが定期的にスレッドを起動し、サーバー処理を実行します。
criatom_library_multi_thread_timer_driven.png

マルチスレッドフレームワーク(タイマー駆動式)の概念

注意:
タイマー駆動式を選択する場合でも、サーバー処理関数として criAtomEx_ExecuteMain関数 を定期的に実行する必要があります。
(デコード処理やファイルアクセス完了待ち等、時間のかかる処理は全てライブラリが作成したスレッド上で実行されますが、極短時間で終わる処理がいくつか実行される可能性があります。)
ユーザ駆動式について

ユーザ駆動時は、ユーザが criAtomEx_ExecuteMain関数 を実行したタイミングでスレッドが起動され、サーバー処理が実行されます。
criatom_library_multi_thread_user_driven.png

マルチスレッドフレームワーク(ユーザ駆動式)の概念

ユーザマルチスレッドフレームワーク

初期化処理時にユーザマルチスレッドフレームワークを選択した場合、ライブラリはスレッドを作成しません。
しかし、サーバー処理が複数スレッドから同時に実行された場合でも正常に動作するよう、共有リソースへアクセスを排他制御します。
ユーザマルチスレッドフレームワーク使用時は、サーバー処理関数として criAtomEx_ExecuteAudioProcess関数 を定期的に実行する必要があります。
マルチスレッドモード時の criAtomEx_ExecuteMain関数とは異なり、呼び出したスレッドでサーバー処理が実行されます。
criatom_library_user_multi_thread.png

ユーザマルチスレッドフレームワークの概念

注意:
ユーザマルチスレッドフレームワーク時にストリーム再生を行う場合、 criAtomEx_ExecuteMain 関数を実行しないでください。
criAtomEx_ExecuteMain 関数内でファイル読み込み完了待ちが発生するため、関数内で数Vの間処理がロックされます。)
ストリーム再生を行う場合、メインスレッド上では criAtomEx_ExecuteAudioProcess 関数のみを実行し、 他のスレッド上で criFs_ExecuteFileAccess 関数や criFs_ExecuteDataDecompression 関数を実行してください。

シングルスレッドフレームワーク

初期化処理時にシングルスレッドフレームワークを選択した場合、ライブラリはスレッドを作成しません。
また、サーバー処理が複数スレッドから同時に実行されることを想定しないため、共有リソースへアクセスも排他制御されません。
シングルスレッドフレームワーク使用時は、サーバー処理関数として criAtomEx_ExecuteMain関数 を定期的に実行する必要があります。
マルチスレッドモード時の criAtomEx_ExecuteMain 関数とは異なり、呼び出したスレッドでサーバー処理が実行されます。
criAtomEx_ExecuteMain 関数内でオーディオ、ファイルアクセス、データ展開処理のすべてを行うため、処理時間が1Vを超える可能性があります。)
criatom_library_single_thread.png

シングルスレッドフレームワークの概念

注意:
シングルスレッドフレームワーク時にファイル読み込みを行うと、criAtomEx_ExecuteMain関数の処理時間はほとんどの場合1Vを超えます。
ストリーム再生を行う場合はシングルスレッドフレームワークを使用せず、他のフレームワークを選択してください。

スレッドセーフかどうか

モジュールごとの安全性

CRI Atomライブラリの関数がスレッドセーフにできているかどうかは、モジュールによって異なります。
モジュールごとのマルチスレッドアクセスへの対応状況は以下のとおりです。
マルチスレッドアクセスへの対応状況
モジュール スレッドセーフかどうか 補足
CriAtomEx API スレッドセーフではありません 一部例外的にスレッドセーフな関数もあります(後述)
CriAtomExPlayer API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriAtomExVoicePool API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriAtomExAcb API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriAtomPlayer API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriAtomAwb API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriAtomHcaMx API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriAtomAsr API スレッドセーフではありません 1つのハンドルを複数のスレッドから同時にアクセスした場合、問題が発生します
CriErr API スレッドセーフではありません  

複数ハンドルを使用する場合

スレッドセーフではないAPIを呼び出すケースでも、スレッド毎に異なるハンドルを使用している場合は、同じ関数を同時に実行しても問題ありません。
例えば、criAtomExPlayer_SetCueId 関数はスレッドセーフではありませんが、スレッド毎に異なる CriAtomExPlayer ハンドルを作成して、criAtomExPlayer_SetCueId 関数を呼び出すことは可能です。

具体的な例としては、以下のようなケースが挙げられます。
void thread_func1(void)
{
    CriAtomExPlayerStatus player_status;
    player_1 = criAtomExPlayer_Create(&player_config, NULL, 0);
    criAtomExPlayer_SetCueId(player_1, acb_hn, CRIATOMEX_CUE_BOMB2);
    
    for (;;) {
        player_status = criAtomExPlayer_GetStatus(player_1);
        if (player_status == CRIATOMEXPLAYER_STATUS_PLAYEND) {
            break;
        }
        
        criAtomEx_ExecuteMain();
        sleep(10);
    }
    criAtomExPlayer_Destroy(player_1);
}

void thread_func2(void)
{
    CriAtomExPlayerStatus player_status;
    player_2 = criAtomExPlayer_Create(&player_config, NULL, 0);
    criAtomExPlayer_SetCueId(player_2, acb_hn, CRIATOMEX_CUE_THUNDER3);
    
    for (;;) {
        player_status = criAtomExPlayer_GetStatus(player_2);
        if (player_status == CRIATOMEXPLAYER_STATUS_PLAYEND) {
            break;
        }
        
        criAtomEx_ExecuteMain();
        sleep(10);
    }
    criAtomExPlayer_Destroy(player_2);
}


上記コード中の thread_func1 と thread_func2 が2つのスレッドで同時に実行されたとしても、特に問題は発生しません。

例外的にスレッドセーフな関数

モジュール自体がスレッドセーフではない場合でも、以下の関数は例外的にスレッドセーフにできています。

これらの関数は、同一モジュールの他の関数と同時に実行した場合でも、問題なく動作します。

リソースの解放に関する注意

ライブラリの終了処理( criAtomEx_Finalize 関数)や、ハンドルを破棄する関数( criAtomExPlayer_Destroy 関数等)は、すべてのライブラリ(ハンドル)リソースを解放します。
そのため、たとえスレッドセーフな関数を実行中であっても、別スレッドでこれらの関数を実行した場合には、アクセス違反等の重大な問題を引き起こす可能性があります。

Next:ワークメモリについて

CRI Middleware logo Copyright (c) 2006-2018 CRI Middleware Co., Ltd.