1

コールバック (snd_async_add_pcm_handler()) で ALSA を非同期モードで使用します。すべての ALSA のコールバックは、SIGIO シグナル ハンドラから呼び出されます。すべてのコールバックが私の関数getCurrentTimeMs()を呼び出します:

// Return current milliseconds (don't care - local time or UTC).
long long getCurrentTimeMs(void)
{
    std::cout << "+"; std::cout.flush();
    long long ret = 0;

#define Z
#ifdef Z
    struct timespec ts;
    clock_gettime( CLOCK_MONOTONIC, &ts);
    ret = ts.tv_sec * 1000;
    ret += ts.tv_nsec / 1000000;
#else
    boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
    std::cout << "."; std::cout.flush();
    boost::posix_time::ptime    epoch_start(boost::gregorian::date(1970,1,1));
    std::cout << "."; std::cout.flush();
    boost::posix_time::time_duration dur = now - epoch_start;
    std::cout << "."; std::cout.flush();
    ret = dur.total_milliseconds();
#endif
    std::cout << "-"; std::cout.flush();
    return ret;
}

  • シグナル ハンドラは、前のハンドラが終了する前に呼び出すことができます。
  • 正確なサンプルレートを測定するには、ミリ秒単位の現在の時間が必要です。

    #define Zにコメントすると、ブーストが使用されます。「ブースト モード」では、オーディオの再生開始から予測できない時間が経過すると、アプリケーションがハングします。strace show アプリケーションはこれでハングします:

        書き込み (1、「+」...、1) = 1
        gettimeofday({1332627252, 660534}, NULL) = 0
        futex(0xb68dba4c, FUTEX_WAIT_PRIVATE, 2, NULL <未完成 ...>
    

    しかし、0xb68dba4cはすべてのトレース ログで 2 ~ 3 回しか発生しませんでした。futex(0xb68dba4c ...は、すべての getCurrentTimeMs() 呼び出しで発生するものではありません。しかし、それが発生すると、すべてがハングし、そのgettimeofdayの後にのみ発生します。コンソールに「+.」が表示され、そのfutexが発生します。しかしその前に、アプリケーションは毎秒 50 回、各コールバックでgetCurrentTimeMs()を呼び出して、大量のサウンドを再生できます。

    #define Zを使用すると、私のコードが使用されます。この場合、アプリケーションは問題なく動作し、数ギガバイトの WAV ファイルをハングすることなく再生できます。

    アプリケーションには、boost::threadpool を介して実行される 2 つのスレッドがあり、両方ともgetCurrentTimeMs()を使用します。デッドロック エラーがあると仮定します。しかし、 #define Zがそれにどのように影響するかはわかりません。

    編集: 私の質問はこのように答えられ、私はこの答えを受け入れます:
    1) http://permalink.gmane.org/gmane.linux.alsa.devel/96282
    2) http://answerpot.com/showthread.php? 3448138-ALSA+async+callback+re-enter+and+DEADLOCK .

  • 4

    1 に答える 1

    1

    これが私にはどのように見えるかというと、考慮すべき非同期スケジューリングには、非同期スレッドと非同期割り込み(「シグナル」)の2種類があります。スレッドは、明示的に同期しない限り、互いに独立して実行されます。シグナルは非同期でスケジュールされますが、配信先のスレッドをプリエンプトしてブロックします。呼び出しているブースト関数またはiostreamは、ロックによってスレッドセーフを実現しているように見えます。これにより、ハンドラーがプリエンプトしたスレッドがすでにロックを保持している可能性があるため、割り込みハンドラーを呼び出すのは_un_safeになります。

    あなたがするかもしれない一つのことは、他に何もしないスレッドにすべての信号を配信するように手配することです-おそらく起動時にすぐにスレッドを起動し、そこでメインラインコードを実行し、元のメインスレッドを信号処理専用のままにします。

    于 2012-03-25T01:43:48.383 に答える