Когда мне нужна структура данных без блокировки для чтения / записи данных между потоками в аудио-приложениях? - PullRequest
4 голосов
/ 13 февраля 2012

Мой сценарий выглядит примерно так: пользователь взаимодействует с элементами графического интерфейса, функция обратного вызова аудио считывает переменные, установленные пользовательским интерфейсом, вычисляет выборки и сохраняет выборки в буфере (или любой другой структуре данных), затем буфер считывается пользовательским интерфейсом и рисует форма волны (в цикле отрисовки 60 раз в секунду).

Теперь, согласно некоторым вещам, которые я прочитал (поток в списке аудиоустройств Linux, это и это ), мне нужна какая-то структура данных, которую можно прочитать и пишется одновременно, не требуя блокировки, или мне нужна какая-то система межпотоковых уведомлений для передачи переменных.

Однако, некоторые примеры Я видел использование ванильных векторов из библиотеки C ++ std, они читают из одного потока и пишут из другого, а когда я запускаю программы, они беги нормально.

  1. В каких случаях мне нужно использовать структуру данных без блокировок?
  2. Если я добавлю другой поток, такой как функция обратного вызова MIDI или OSC, который получает сетевой ввод-вывод и должен передавать данные двум другим потокам, нужно ли мне беспокоиться о структурах без блокировки?
  3. Какую структуру использовать, если ответом на номер два будет «да»?

1 Ответ

6 голосов
/ 13 февраля 2012

Если у вас есть потоки, которые обращаются к одной и той же памяти (чтение или запись), то вам нужно либо использовать блокировки, либо использовать структуру данных без блокировки. В противном случае ваши структуры данных могут быть повреждены (или выглядеть поврежденными), когда к ним одновременно обращается более чем один поток.

Похоже, что примеры, на которые вы указываете, используют вектор фиксированного размера, который выделяется раньше времени. Аудиопоток записывает в этот буфер, а поток пользовательского интерфейса читает его, и эти два не синхронизированы. Поскольку эти два могут выполняться полностью одновременно, поток пользовательского интерфейса не имеет никаких гарантий относительно того, какие данные на самом деле читаются; он может прочитать некоторые данные из обновления N и некоторые из обновления N + 1. Это может пропустить некоторые данные или прочитать некоторые данные дважды (или больше). Это не надежный способ создания аудио приложений. Он будет «работать» достаточно хорошо для простого приложения визуализации, потому что результаты визуализации не обязательно должны быть идеальными, но это будет совершенно непригодно для приложения записи или воспроизведения.

В аудиоприложениях часто используются структуры данных без блокировок (вместо использования блокировок), поскольку для воспроизведения звука требуются требования в режиме реального времени. Если ваши звуковые буферы содержат 100 мс звука, то вам необходимо заполнять эти буферы 10 раз в секунду, иначе воспроизведение звука будет зависать. Другой способ сказать, что у вас есть 100 мс срок для заполнения буфера каждый раз.

Есть множество вещей, которые могут заставить вас пропустить этот срок в 100 мс; если система слишком занята, ваш процесс может не быть запланирован или сбой страницы может привести к чтению диска, которое блокирует процесс на слишком длительный срок, просто назовите пару примеров. Если вы пытаетесь получить блокировку, но другой поток удерживает ее более 100 мс, это заставит вас пропустить срок. Вот почему использование блокировок может быть плохо для аудио приложений; другая нить, которая слишком долго удерживает блокировку, может заставить вас пропустить свой срок.

При структуре данных без блокировок ждать не приходится, поэтому другие потоки не могут остановить ваш прогресс. Это упрощает сроки подачи аудио ввода / вывода.

Но прежде чем вы слишком увлечетесь алгоритмами без блокировок, вы должны знать, что они гораздо более тонкие и требуют гораздо большего опыта для правильного использования, чем блокировки. По сути, если вы не специалист в этой области, вы не должны пытаться самостоятельно писать алгоритмы без блокировок. Возможно, есть хорошая библиотека с открытым исходным кодом, которая имеет некоторые реализации алгоритмов без блокировок; Я не смотрел в последнее время.

Но поймите, что дополнительная работа, необходимая для использования алгоритмов без блокировок, более или менее напрасна, если вы не будете слишком осторожны в аудио-потоке, чтобы избежать других возможных причин задержки. В частности:

  • ваш аудиопоток не должен malloc() или free() никакой памяти (большинство реализаций malloc / free получают глобальную блокировку внутренне)

  • вы должны убедиться, что любая память, к которой обращается ваш аудиопоток, не выгружена (например, mlock())

  • ваш аудиопоток не должен выполнять никаких операций ввода-вывода, кроме как со звуковой картой, поскольку вызовы ввода-вывода могут блокироваться.

Если вы не очень усердны и не выполняете все эти шаги, вы также можете использовать блокировку для данных, которая используется совместно с другими потоками, но убедитесь, что блокировка удерживается в течение очень короткого промежутка времени. Например, не выполняйте никаких вызовов malloc () / free () или системных вызовов в потоке пользовательского интерфейса с удерживаемой блокировкой.

...