LoginSignup
1
2

More than 3 years have passed since last update.

pthread_cond_timedwaitとpthread_cond_timedwait_relative_npに惑わされた話

Posted at

前置き

  • 内製ツールでpthread_cond_timedwaitを使って数秒waitさせたい処理が、実はwaitできてなかった

どういうこと?

  • プリプロセッサシンボルの定義状態から、 pthread_cond_timedwaitpthread_cond_timedwait_relative_np とを使い分ける処理が存在
  • 使い方のノリがほぼ一緒であった
  • Androidの64bit対応する折に、 error: '::pthread_cond_timedwait_relative_np' has not been declared となり、releative_npの方を使わないようにする対応が必要となった
  • そのまま処理を流用したら、なぜか全くwaitしてくれなくなった

こんなイメージ

XXXThread.cpp
#if XXX //今まではこっちが通るようにシンボル定義してあった
    struct timespec ts;
    long sec = timeoutInUsec / 1000000;
    long mod_sec = timeoutInUsec % 1000000;
    ts.tv_sec = sec;
    ts.tv_nsec = mod_sec * 1000;
    int result = ::pthread_cond_timedwait_relative_np(&m_signal, &m_mutex, &ts);
#else  //★今回の対応で通るようになったスコープはコチラ
    struct timespec ts;
    long sec = timeoutInUsec / 1000000;
    long mod_sec = timeoutInUsec % 1000000;
    time_t now = 0;
    ts.tv_sec = sec + time(&now);
    ts.tv_nsec = mod_sec * 1000;
    int result = ::pthread_cond_timedwait(&m_signal, &m_mutex, &ts);
#endif

なんでか?

pthread_cond_timedwait_relative_np は名前の通り、相対時間を入力にwaitしてくれる。
対して pthread_cond_timedwait は絶対日時を入力にwaitしてくれる。
つまり、上記のイメージの処理だと、 nsecの指定を ts.tv_nsec = mod_sec * 1000; としているが、これは相対時間なので、ほぼほぼ実時間未満の数値が入り、想定している時間でwaitできてなかった。

つまりこんな感じで修正すれば最終的にOKだった

  • clock_gettimeでnsecの精度で現在時刻を取得するようにした
  • 現時刻をベースにwaitしたい時間を加算してあげるようにした
  • 桁あふれを考慮した
XXXThread.cpp
#if XXX //今まではこっちが通るようにシンボル定義してあった
    struct timespec ts;
    long sec = timeoutInUsec / 1000000;
    long mod_sec = timeoutInUsec % 1000000;
    ts.tv_sec = sec;
    ts.tv_nsec = mod_sec * 1000;
    int result = ::pthread_cond_timedwait_relative_np(&m_signal, &m_mutex, &ts);
#else  //★今回の対応で通るようになったスコープはコチラ
    struct timespec ts;
    long sec = timeoutInUsec / 1000000;
    long mod_sec = timeoutInUsec % 1000000;
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += sec;
    ts.tv_nsec+= mod_sec * 1000;
    if (1000000000 <= ts.tv_nsec)
    {
        ts.tv_nsec -= 1000000000;
        ts.tv_sec  += 1;
    }
    result = ::pthread_cond_timedwait(&m_signal, &m_mutex, &ts);
#endif

参考

1
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2