crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

4 страниц V   1 2 3 > »   
Ответить в данную темуНачать новую тему
> Сложная синхронизация
mezmay
  опции профиля:
сообщение 27.12.2014, 6:40
Сообщение #1


Активный участник
***

Группа: Участник
Сообщений: 272
Регистрация: 13.7.2009
Из: Ростов-на-Дону
Пользователь №: 904

Спасибо сказали: 16 раз(а)




Репутация:   1  


Работаю с 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 и поток обработки звука. Как ясно из первого сообщения, в потоке обработки звука нельзя пользоваться мьютексами и т.д. И есть как минимум пять переменных :

int shift_left;
float volume_left;
float volume_right
Filter *filter_left;
Filter *filter_right;

shift_left - текущая задержка левого канала,
volume_left, volume_right - громкость каналов.

GUI поток пишет значения этих переменных, поток обработки звука - читает. Как синхронизировать? Особенно интересуют объекты типа Filter...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
FireBlack
  опции профиля:
сообщение 27.12.2014, 7:15
Сообщение #2


Студент
*

Группа: Участник
Сообщений: 38
Регистрация: 17.10.2010
Из: г.Пенза
Пользователь №: 2121

Спасибо сказали: 13 раз(а)




Репутация:   1  


Цитата(mezmay @ 27.12.2014, 6:40) *
GUI поток пишет значения этих переменных, поток обработки звука - читает. Как синхронизировать? Особенно интересуют объекты типа Filter...

А если просто отправлять эти значения из GUI потока с помощью сигнала, а в потоке обработке звука ловить их слотом?! Только сконнектить их с помощью Queued Connection. Однако, учтите, что в потоке обработке звука должен быть свой QEventLoop.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mezmay
  опции профиля:
сообщение 27.12.2014, 8:06
Сообщение #3


Активный участник
***

Группа: Участник
Сообщений: 272
Регистрация: 13.7.2009
Из: Ростов-на-Дону
Пользователь №: 904

Спасибо сказали: 16 раз(а)




Репутация:   1  


Я не управляю этим потоком, только callback задаю
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mezmay
  опции профиля:
сообщение 27.12.2014, 11:07
Сообщение #4


Активный участник
***

Группа: Участник
Сообщений: 272
Регистрация: 13.7.2009
Из: Ростов-на-Дону
Пользователь №: 904

Спасибо сказали: 16 раз(а)




Репутация:   1  


Хотя можно получить posix thread id, а значит наверное и QThread создать...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 27.12.2014, 20:30
Сообщение #5


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Используйте например
http://qt-project.org/doc/qt-4.8/qatomicint.html
http://qt-project.org/doc/qt-4.8/qatomicpointer.html

Это если вы создаете объект типа фильтр в коллбэке и подменяете.
Если же вы просто используете разделяемый объект, то все сложнее, но направление то-же, используйте атомарные операции, они дешевле мьютексов.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 27.12.2014, 23:08
Сообщение #6


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


если я правильно понимаю идею, то это вообще изначально неверно организована работа с риалтаймовскими данными. обычно в callback'е данные только складываются в некий буфер. а потом уже другой поток их читает и что-то с ними делает. в этом другом потоке делай хоть что. а в callback'е никаких ожиданий быть не может. обычно делается кольцевой буфер, туда пишутся данные и атомарно меняются указатели на конец данных. а читающий поток атомарно меняет указатель на начало данных.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mezmay
  опции профиля:
сообщение 9.1.2015, 15:09
Сообщение #7


Активный участник
***

Группа: Участник
Сообщений: 272
Регистрация: 13.7.2009
Из: Ростов-на-Дону
Пользователь №: 904

Спасибо сказали: 16 раз(а)




Репутация:   1  


Цитата(Iron Bug @ 27.12.2014, 23:08) *
если я правильно понимаю идею, то это вообще изначально неверно организована работа с риалтаймовскими данными. обычно в callback'е данные только складываются в некий буфер. а потом уже другой поток их читает и что-то с ними делает. в этом другом потоке делай хоть что. а в callback'е никаких ожиданий быть не может. обычно делается кольцевой буфер, туда пишутся данные и атомарно меняются указатели на конец данных. а читающий поток атомарно меняет указатель на начало данных.


Но в родном примере:
/**
* The process callback for this JACK application.
* It is called by JACK at the appropriate times.
*/
int process (jack_nframes_t nframes, void *arg)
{
    jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
    jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes);

    memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);
  
    return 0;      
}


Цитата
int jack_set_process_callback ( jack_client_t * сlient, 
    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.


Как тут можно использовать дополнительный буфер, ведь данные принимаются и отправляются в одном месте?

Сообщение отредактировал mezmay - 9.1.2015, 17:47
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mezmay
  опции профиля:
сообщение 9.1.2015, 17:49
Сообщение #8


Активный участник
***

Группа: Участник
Сообщений: 272
Регистрация: 13.7.2009
Из: Ростов-на-Дону
Пользователь №: 904

Спасибо сказали: 16 раз(а)




Репутация:   1  


Вот полистал API, обратил внимание на функцию в разделе Creating and managing client threads:

Цитата
int jack_client_create_thread    (    jack_client_t *     client,
jack_native_thread_t *     thread,
int     priority,
int     realtime,
void *(*)(void *)     start_routine,
void *     arg
)

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.1.2015, 19:02
Сообщение #9


Активный участник
***

Группа: Участник
Сообщений: 272
Регистрация: 13.7.2009
Из: Ростов-на-Дону
Пользователь №: 904

Спасибо сказали: 16 раз(а)




Репутация:   1  


Не знаю как это реализовать, но правильно работать было бы так:
у нас два потока A - GUI поток и B - поток обработки и ввода/вывода звука.
Все переменные, используемые в обработке звука, должны "жить" в потоке B (в котором должен крутиться QEventLoop). Если их (данные) надо изменить из A (GUI), то делаем это через Queued Connection...

Сообщение отредактировал mezmay - 10.1.2015, 9:01
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 10.1.2015, 13:13
Сообщение #10


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Все верно, в потоке B устанавливаете нужный коллбэк, потом запускаете event loop. В этом коллбэке делаете всю обработку и выводите данные.
Коллбэк через void*args связан с объектом, который живет в потоке B - так получаете все нужные параметры для обработки.
Поток А через Queued connection выставляет параметры на объекк в B, Qt делает всю синхронизацию.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

4 страниц V   1 2 3 > » 
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 25.4.2024, 15:44