Многопоточное приложение GtK+3.0
Вот моя проблема: я разрабатываю многопоточное приложение, состоящее из:
- GUI поток-> GTK
- вспомогательный поток -> проверка соединения с сервером JACK
- RT нить джека -> занимаюсь звуком
Я реализовал виджет кнопки, который получает только сигналы от помощника и потока RT, которые изменяют графический интерфейс в своей функции обратного вызова.
Итак, мой вопрос: кто модифицирует графический интерфейс? вспомогательный /RT поток или графический интерфейс, в котором я использовал gtk_main()?
Спасибо за ваше сотрудничество!
edit: я добавил код / ** @file JPLowPassFilter.c * * @brief, это простой клиент, который реализует числовой низкочастотный фильтр */
#include "JPLowPassFilter.h"
jack_port_t *input_port;
jack_port_t *output_port;
jack_default_audio_sample_t tmp;
int first=1;
appData* mainData;
jack_default_audio_sample_t tmp;
/*Code for port_registration_callback */
void registrationPort(jack_port_id_t port, int reg, void *arg)
{
return;
}
/*Code for client_registration_callback */
void registrationClient(const char* name, int reg, void *arg)
{
return;
}
/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
* Must not block!
*/
int process (jack_nframes_t nframes, void *arg)
{
int i;
float alfa=mainData->alfa;
jack_default_audio_sample_t *in, *out;
in = jack_port_get_buffer (input_port, nframes);
out = jack_port_get_buffer (output_port, nframes);
for( i=0; i<nframes; i++) {
if(first==1){
tmp=in[i];
first=0;
}
else{
tmp=tmp*alfa+(1.0f-alfa)*in[i];
//tmp=tmp*(1.0f-alfa)+alfa*in[i];
}
out[i]=tmp;
}
//fprintf (stderr, ".");
return 0;
}
/**
* JACK calls this shutdow_callback if the server ever shuts down or
* decides to disconnect the client
*/
void jack_shutdown (void *arg)
{
mainData->state=NOT_WORKING;
jack_port_unregister(mainData->client,input_port);
jack_port_unregister(mainData->client, output_port);
g_signal_emit_by_name (GTK_BUTTON(mainData->init),"clicked");
}
/* JACK calls this function whenever there is an xrun */
int xrun_function(void *arg)
{
fprintf (stderr, "--XRUN OCCURRED--\n");
}
void* threadCode(void* val)
{
const char *client_name = CLIENT_NAME;
const char *server_name = NULL;
mainData=(appData*) val;
/* if server isn't present, don't start it!*/
jack_options_t options =JackNoStartServer;
jack_status_t status;
do{
/* try to open a client connection to the JACK server */
mainData->client = jack_client_open (client_name, options, &status, server_name);
if (mainData->client == NULL)
{
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf (stderr, "Unable to connect to JACK server\n");
}
sleep(3);
}
else
{
fprintf (stderr, "Connected to JACK server\n");
mainData->state=INIT;
/* CALLBACKS*/
jack_set_process_callback (mainData->client, process, 0);
jack_on_shutdown (mainData->client, jack_shutdown, mainData);
jack_set_xrun_callback(mainData->client,xrun_function, 0);
jack_set_port_registration_callback (mainData->client, registrationPort,NULL);
jack_set_client_registration_callback(mainData->client, registrationClient,NULL);
/* PORTS */
input_port = jack_port_register (mainData->client, "input", JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput, 0);
output_port = jack_port_register (mainData->client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
mainData->state=INIT;
if ((input_port == NULL) || (output_port == NULL))
{
fprintf(stderr, "no more JACK ports available\n");
mainData->state=NOT_WORKING;
}
/* STARTS */
else if (jack_activate (mainData->client)) {
fprintf (stderr, "cannot activate client");
jack_port_unregister(mainData->client,input_port);
jack_port_unregister(mainData->client, output_port);
mainData->state=NOT_WORKING;
}
else
{
fprintf (stderr, "Client ready to Run\n");
mainData->state=WORKING;
mainData->portsName[0]=jack_port_name(input_port);
mainData->portsName[1]=jack_port_name(output_port);
}
//can be written to
mainData->inputList=jack_get_ports(mainData->client,NULL, NULL,JackPortIsInput);
//can be read from
mainData->outputList=jack_get_ports(mainData->client,NULL, NULL,JackPortIsOutput);
g_signal_emit_by_name (GTK_BUTTON(mainData->init),"clicked");
while(mainData->state==WORKING)
{
sleep(5);
fprintf (stderr, ".");
}
fprintf (stderr, "\n");
jack_free(mainData->inputList);
jack_free(mainData->outputList);
mainData->outputList=NULL;
mainData->inputList=NULL;
jack_client_close (mainData->client);
}
fprintf (stderr, "---RECONNECT---\n");
}while(mainData->state==NOT_WORKING);
fprintf (stderr, "Ended!\n");
pthread_exit(NULL);
}
1 ответ
После комментариев предлагается обменяться g_signal_emit_by_name
функции для g_async_queue_*
функции.
Предположим, что mainData->init
указывает на GAsyncQueue, созданный в главном потоке вместо фактической кнопки.
Тогда вы можете использовать в своей теме:
g_async_queue_push(G_ASYNC_QUEUE(mainData->init), data);
Данные могут содержать простой флаг для обозначения статуса и / или изменения статуса
Затем в главном потоке, когда вы настраиваете пользовательский интерфейс, вы можете добавить обработчик простоя с помощью:
my_queue = g_async_queue_new();
...
g_idle_add ((GSourceFunc) check_async_queue, my_queue);
и ваш check_async_queue
может быть что-то вроде этого:
gboolean check_async_queue (gpointer user_data) {
gpointer queue_data;
queue_data = g_async_queue_try_pop (G_ASYNC_QUEUE(user_data));
if (queue_data != NULL) {
// We have data, do something with 'queue_data'
// and update GUI
} else {
// no data, probably do nothing
}
return TRUE; // can be G_SOURCE_CONTINUE instead of TRUE
}
Возвращаемое значение будет указывать, если check_async_queue
Функция должна продолжать работать или нет, так что вы можете иметь условие, чтобы удалить функцию.
Это позволит вам иметь простую одностороннюю очередь сообщений, которую вы можете использовать для передачи информации из рабочего потока в основной поток.