LINUX.ORG.RU

Может ли функция signal handler вызываться ЕЩЁ РАЗ во время того, как она уже выполняется?


0

2

Сабж.

Делаю тут ALSA-воспроизводилку звука, вся загрузка данных из файла - в отдельном потоке. Используются два больших раздельных буфера, объёма достаточного для хранения примерно 8 секунд при 44100/16. Загрузка данных во второй - когда ещё только начал воспроизводиться первый. Даже если за 8 секунд параллельный поток не успел прочитать данные с диска (что невероятно), ничего не произойдёт и воспроизводиться будет мусор. Переключение между блоками - пара операций сравнения, перезапись пары переменных, т.е. ерунда.

ALSA просит данные по коллбеку. За раз в неё отправляется примерно 940 фреймов (фрейм = sizeof(short)*channels). То есть коллбеки происходят 46 раз в секунду.

В неопределённом месте - всегда по-разному - после минуты или после 10 минут звучания всё виснет нафиг, причём все потоки сразу. 10 минут - это тот срок, когда все механизмы уже успели отработать по многу раз - и загрузка данных и переключение между буферами и т.п. Т.е. всё классно и без щелчков звучит. Отладка показала, что в момент зависания происходит уникальное событие - когда только начал выполняться коллбек ALS-Ы, в него делается ещё один заход. То есть предыдущий handler не успел выполниться, начинается его выполнение ещё раз. Читал, что коллбеки ALSA инициируются сигналами. То есть библиотека ловит сигнал, вызывает переданную ей функцию, которая и есть мой хендлер.

1. Возможно ли такое вообще? 2. Если он вызвался второй раз, когда ещё идёт выполнение первого - значит в деле учавствуют 2 каких-то потока? 3. Какой поток/процесс вызывает обработчики сигналов для процесса в linux? Т.е. в контексте какого «control flow» идёт исполнение кода обработчика сигнала? Как такое возможно? В гугл не отсылайте пожалуйста, просто напишите как это возможно и всё (-; (-; (-; 4. И чё делать :) ? В хэндлере поубирал все std::cout, никаких выделений памяти, никаких тяжёлых операций - работа только с заранее выделенной памятью, переменными класса и т.п. - всё равно случается жОсткий зависон изредка.

    void MyALSACallback()
    {
        std::cout << "1"; std::cout.flush();
        // ... snd_pcm_writei() call ... //
        // ... no any returns ... //
        std::cout << "2"; std::cout.flush();
        return;
    }

Когда всё хорошо, в консоли валится «1212121212...», перед зависанием встречается уникальная последовательность «11».

Короче главный вопрос - вопрос из сабжа.

Спасибо.

★☆

Последнее исправление: kiverattes (всего исправлений: 2)

ну нарисуй здесь колбэк-функцию для алсы и функцию переключения буферов; телепаты в отпуске

anonymous
()

ну, у тебя же два потока в приложении, вот и получается, что увидеть два обработчика одновременно - вопрос времени

anonymous
()

Возможно ли такое вообще?

Да, возможно. Сигнал может прийти еще раз, пока обработчик работает. Чтобы этого не было, устанавливайте обработчик сигнала с помощью sigaction без флага SA_NODEFER - это гарантирует, что обработчик сигнала не будет прерван сигналом (сигнал подождет завершения обработчика).

Какой поток/процесс вызывает обработчики сигналов для процесса в linux?

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

Т.е. в контексте какого «control flow» идёт исполнение кода обработчика сигнала?

В контексте какой-либо нити процесса. 2 варианта: либо используется alternate stack, либо прямо в стеке нити. Функция обработчика вызывается таким образом, что она вернется ровно в то место, где нить была прервана.

Если он вызвался второй раз, когда ещё идёт выполнение первого - значит в деле учавствуют 2 каких-то потока?

Возможны разные варианты.

И чё делать :)

Есть такое хорошее правило - в обработчике сигнала ничего не делать :)

dmitry_vk ★★★
()

да, может. Я у себя в программе блокирую внутри тела обработчика прием определенных сигналов, т.к. мне это не нужно

Pinkbyte ★★★★★
()

Я не знаю, как работает ALSA, но, мне кажется, что там есть и более интересные API. Например, на основе callback'ов.

dmitry_vk ★★★
()
Ответ на: комментарий от kiverattes

Еще можно сделать цикл, в котором ожидать прихода сигнала с помощью waitsignal или signalfd - тут не будет никаких проблем с асинхронностью.

dmitry_vk ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.