![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
mezmay |
![]() ![]()
Сообщение
#1
|
![]() Активный участник ![]() ![]() ![]() Группа: Участник Сообщений: 272 Регистрация: 13.7.2009 Из: Ростов-на-Дону Пользователь №: 904 Спасибо сказали: 16 раз(а) Репутация: ![]() ![]() ![]() |
Работаю с Jack audio connection kit API, нужна обработка звука в "реальном" времени. Сама обработка делается в callback-функции, вызываемой из другого потока. Но в описании сказано, что нельзя применять длительные операции, в т.ч. мьютексы. Но как тогда работать с общими с основным потоком данными? Какие варианты?
Цитата int jack_set_process_callback ( jack_client_t * client, JackProcessCallback process_callback, void * arg ) Tell the Jack server to call process_callback whenever there is work be done, passing arg as the second argument. The code in the supplied function must be suitable for real-time execution. That means that it cannot call functions that might block for a long time. This includes all I/O functions (disk, TTY, network), malloc, free, printf, pthread_mutex_lock, sleep, wait, poll, select, pthread_join, pthread_cond_wait, etc, etc. Итак, у меня два потока - GUI и поток обработки звука. Как ясно из первого сообщения, в потоке обработки звука нельзя пользоваться мьютексами и т.д. И есть как минимум пять переменных :
shift_left - текущая задержка левого канала, volume_left, volume_right - громкость каналов. GUI поток пишет значения этих переменных, поток обработки звука - читает. Как синхронизировать? Особенно интересуют объекты типа Filter... |
|
|
FireBlack |
![]()
Сообщение
#2
|
![]() Студент ![]() Группа: Участник Сообщений: 38 Регистрация: 17.10.2010 Из: г.Пенза Пользователь №: 2121 Спасибо сказали: 13 раз(а) Репутация: ![]() ![]() ![]() |
GUI поток пишет значения этих переменных, поток обработки звука - читает. Как синхронизировать? Особенно интересуют объекты типа Filter... А если просто отправлять эти значения из GUI потока с помощью сигнала, а в потоке обработке звука ловить их слотом?! Только сконнектить их с помощью Queued Connection. Однако, учтите, что в потоке обработке звука должен быть свой QEventLoop. |
|
|
mezmay |
![]()
Сообщение
#3
|
![]() Активный участник ![]() ![]() ![]() Группа: Участник Сообщений: 272 Регистрация: 13.7.2009 Из: Ростов-на-Дону Пользователь №: 904 Спасибо сказали: 16 раз(а) Репутация: ![]() ![]() ![]() |
Я не управляю этим потоком, только callback задаю
|
|
|
mezmay |
![]()
Сообщение
#4
|
![]() Активный участник ![]() ![]() ![]() Группа: Участник Сообщений: 272 Регистрация: 13.7.2009 Из: Ростов-на-Дону Пользователь №: 904 Спасибо сказали: 16 раз(а) Репутация: ![]() ![]() ![]() |
Хотя можно получить posix thread id, а значит наверное и QThread создать...
|
|
|
lanz |
![]()
Сообщение
#5
|
![]() Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 690 Регистрация: 28.12.2012 Пользователь №: 3660 Спасибо сказали: 113 раз(а) Репутация: ![]() ![]() ![]() |
Используйте например
http://qt-project.org/doc/qt-4.8/qatomicint.html http://qt-project.org/doc/qt-4.8/qatomicpointer.html Это если вы создаете объект типа фильтр в коллбэке и подменяете. Если же вы просто используете разделяемый объект, то все сложнее, но направление то-же, используйте атомарные операции, они дешевле мьютексов. |
|
|
Iron Bug |
![]()
Сообщение
#6
|
![]() Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: ![]() ![]() ![]() |
если я правильно понимаю идею, то это вообще изначально неверно организована работа с риалтаймовскими данными. обычно в callback'е данные только складываются в некий буфер. а потом уже другой поток их читает и что-то с ними делает. в этом другом потоке делай хоть что. а в callback'е никаких ожиданий быть не может. обычно делается кольцевой буфер, туда пишутся данные и атомарно меняются указатели на конец данных. а читающий поток атомарно меняет указатель на начало данных.
|
|
|
mezmay |
![]() ![]()
Сообщение
#7
|
![]() Активный участник ![]() ![]() ![]() Группа: Участник Сообщений: 272 Регистрация: 13.7.2009 Из: Ростов-на-Дону Пользователь №: 904 Спасибо сказали: 16 раз(а) Репутация: ![]() ![]() ![]() |
если я правильно понимаю идею, то это вообще изначально неверно организована работа с риалтаймовскими данными. обычно в callback'е данные только складываются в некий буфер. а потом уже другой поток их читает и что-то с ними делает. в этом другом потоке делай хоть что. а в callback'е никаких ожиданий быть не может. обычно делается кольцевой буфер, туда пишутся данные и атомарно меняются указатели на конец данных. а читающий поток атомарно меняет указатель на начало данных. Но в родном примере:
Цитата Tell the Jack server to call process_callback whenever there is work be done, passing arg as the second argument. The code in the supplied function must be suitable for real-time execution. That means that it cannot call functions that might block for a long time. This includes all I/O functions (disk, TTY, network), malloc, free, printf, pthread_mutex_lock, sleep, wait, poll, select, pthread_join, pthread_cond_wait, etc, etc. Как тут можно использовать дополнительный буфер, ведь данные принимаются и отправляются в одном месте? Сообщение отредактировал mezmay - 9.1.2015, 17:47 |
|
|
mezmay |
![]()
Сообщение
#8
|
![]() Активный участник ![]() ![]() ![]() Группа: Участник Сообщений: 272 Регистрация: 13.7.2009 Из: Ростов-на-Дону Пользователь №: 904 Спасибо сказали: 16 раз(а) Репутация: ![]() ![]() ![]() |
Вот полистал API, обратил внимание на функцию в разделе Creating and managing client threads:
Цитата Create a thread for JACK or one of its clients. The thread is created executing start_routine with arg as its sole argument. Parameters: client the JACK client for whom the thread is being created. May be NULL if the client is being created within the JACK server. thread place to return POSIX thread ID. priority thread priority, if realtime. realtime true for the thread to use realtime scheduling. On some systems that may require special privileges. start_routine function the thread calls when it starts. arg parameter passed to the start_routine. Returns: 0, if successful; otherwise some error number. но пока не придумал как использовать и надо ли. Сообщение отредактировал mezmay - 9.1.2015, 17:50 |
|
|
mezmay |
![]()
Сообщение
#9
|
![]() Активный участник ![]() ![]() ![]() Группа: Участник Сообщений: 272 Регистрация: 13.7.2009 Из: Ростов-на-Дону Пользователь №: 904 Спасибо сказали: 16 раз(а) Репутация: ![]() ![]() ![]() |
Не знаю как это реализовать, но правильно работать было бы так:
у нас два потока A - GUI поток и B - поток обработки и ввода/вывода звука. Все переменные, используемые в обработке звука, должны "жить" в потоке B (в котором должен крутиться QEventLoop). Если их (данные) надо изменить из A (GUI), то делаем это через Queued Connection... Сообщение отредактировал mezmay - 10.1.2015, 9:01 |
|
|
lanz |
![]()
Сообщение
#10
|
![]() Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 690 Регистрация: 28.12.2012 Пользователь №: 3660 Спасибо сказали: 113 раз(а) Репутация: ![]() ![]() ![]() |
Все верно, в потоке B устанавливаете нужный коллбэк, потом запускаете event loop. В этом коллбэке делаете всю обработку и выводите данные.
Коллбэк через void*args связан с объектом, который живет в потоке B - так получаете все нужные параметры для обработки. Поток А через Queued connection выставляет параметры на объекк в B, Qt делает всю синхронизацию. |
|
|
![]() ![]() ![]() |
![]() |
|
Текстовая версия | Сейчас: 9.4.2025, 14:06 |