Обратный вызов ALSA (обработчик SIGIO) иногда зависает в boost :: posix_time :: microsec_clock :: local_time () - PullRequest
1 голос
/ 25 марта 2012

Я использую ALSA в асинхронном режиме с обратными вызовами (snd_async_add_pcm_handler ()). Каждый обратный вызов 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;
}

Обработчик сигнала может быть вызван до завершения предыдущего обработчика; Мне нужно текущее время в мс для измерения точной частоты дискретизации.

Если я комментирую # определение Z , используется повышение. В «режиме повышения» приложение зависает через непредсказуемое время от начала воспроизведения звука. strace Показать приложение зависает на этом:

    write(1, "+"..., 1)                     = 1
    gettimeofday({1332627252, 660534}, NULL) = 0
    futex(0xb68dba4c, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>

Но 0xb68dba4c происходило только 2 ... 3 раза во всем журнале трассировки. futex (0xb68dba4c ... - это не то, что происходит при каждом вызове getCurrentTimeMs (). Но когда это происходит, все зависает, и это происходит только после этого gettimeofday ; я вижу " +. "на консоли, а затем возникает futex . Но до этого приложение может воспроизводить тонны звука, вызывая getCurrentTimeMs () для каждого обратного вызова 50 раз в секунду. Такая загадка ...

С # определить Z мой код используется. В этом случае приложение прекрасно работает - проигрывает гигабайты WAV-файлов без зависаний.

Приложение имеет 2 потока, работающих через boost :: threadpool, и оба используют getCurrentTimeMs () ; допустим, у меня есть некоторые тупиковые ошибки; но я понятия не имею, как # определяет Z может повлиять на это.

EDIT: На мой вопрос ответили таким образом, и я принимаю этот ответ:
1) http://permalink.gmane.org/gmane.linux.alsa.devel/96282
2) http://answerpot.com/showthread.php?3448138-ALSA+async+callback+re-enter+and+DEADLOCK.

1 Ответ

1 голос
/ 25 марта 2012

Если это так, мне кажется, существует два вида асинхронного планирования: асинхронные потоки и асинхронные прерывания («сигналы»).Потоки работают независимо друг от друга, если они явно не синхронизируются;Сигналы планируются асинхронно, но имеют приоритет и блокируют любой поток, к которому они доставлены.Это очень похоже на то, что функции повышения или iostreams, которые вы вызываете, достигают поточной безопасности, блокируя, что делает их _un_safe для вызова в обработчике прерываний, потому что поток, который обработчик прервал, вполне может уже удерживать блокировку.* Одна вещь, которую вы можете сделать, это организовать доставку всех сигналов в поток, который больше ничего не делает - возможно, запустить поток сразу при запуске и запустить основной код, оставив исходный основной поток, предназначенный для обработки сигналов.

...