GtK+3.0多线程应用
GtK+3.0 multithreaded application
这是我的问题:
我正在开发一个由以下组成的多线程应用程序:
- GUI 线程-> GTK
- 帮助线程 --> 检查与 JACK 服务器的连接
- jack 的 RT 线程 --> 做一些声音阐述的东西
我已经实现了一个按钮小部件,它只接收来自助手和 RT 线程的信号,在其回调函数中修改 gui。
所以,我的问题是:谁在修改 GUI?我使用 gtk_main() ?
的 helper/RT 线程或 gui 线程
感谢您的配合!
编辑:我添加了代码
/** @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);
}
根据评论,建议将 g_signal_emit_by_name
函数替换为 g_async_queue_*
函数。
假设 mainData->init
指向在主线程中创建的 GAsyncQueue 而不是实际按钮。
然后你可以在你的线程上使用:
g_async_queue_push(G_ASYNC_QUEUE(mainData->init), data);
数据可以包含一个简单的标志来指示状态and/or状态变化
然后在您的主线程上,当您设置 UI 时,您可以添加空闲处理程序:
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
}
return值将指示check_async_queue
函数是否应保留运行,因此您可以有条件删除该函数。
这将允许您拥有一个简单的单向消息队列,您可以使用它来将信息从工作线程传递到主线程。
这是我的问题: 我正在开发一个由以下组成的多线程应用程序:
- GUI 线程-> GTK
- 帮助线程 --> 检查与 JACK 服务器的连接
- jack 的 RT 线程 --> 做一些声音阐述的东西
我已经实现了一个按钮小部件,它只接收来自助手和 RT 线程的信号,在其回调函数中修改 gui。
所以,我的问题是:谁在修改 GUI?我使用 gtk_main() ?
的 helper/RT 线程或 gui 线程感谢您的配合!
编辑:我添加了代码 /** @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);
}
根据评论,建议将 g_signal_emit_by_name
函数替换为 g_async_queue_*
函数。
假设 mainData->init
指向在主线程中创建的 GAsyncQueue 而不是实际按钮。
然后你可以在你的线程上使用:
g_async_queue_push(G_ASYNC_QUEUE(mainData->init), data);
数据可以包含一个简单的标志来指示状态and/or状态变化
然后在您的主线程上,当您设置 UI 时,您可以添加空闲处理程序:
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
}
return值将指示check_async_queue
函数是否应保留运行,因此您可以有条件删除该函数。
这将允许您拥有一个简单的单向消息队列,您可以使用它来将信息从工作线程传递到主线程。