Re: main loop & asynchronous queues



Chris Vine wrote:
In your code you didn't create a GMainContext object for each of your
threads, which is the key point. Each thread in which you want a main
loop should call g_main_context_new() which will create a GMainContext
object for the calling thread, then use that to create a GMainLoop
object, then call g_main_loop_run() on it to run it.
I was getting GMainContexts and GMainLoops confused. Thanks for you input, I've learned several things.

The end goal I'm working for is to improve some programs I have that send and receive messages over udp that require "slow" RSA operations for each one. I want to move the RSA and related processing to another thread, so that a worker thread listens for socket input, does some openssl work, then gives a message to the main thread without blocking on sockets or polling mutexes. At the same time the main thread can send a message to a worker thread to be processed before sent instead of slowing down the main thread. The adding of an idle_source to another thread's main loop technique being discussed will certainly do the trick nicely. The more I learn, glib just keeps getting better.

For anyone in the future searching around for more info on this topic, here is a variation of the gtk hello world program I was doing some experiments with. My main question at this point to anyone who might know is, should the idle source get dereferenced / freed somehow? My other question is g_source_attach() working on another thread's GMainContext with atomic operations, will it possibly have to block for access, or I'm I not doing this in a thread safe way?


/* build with gcc source.c `pkg-config --cflags --libs gtk+2.0 gthread-2.0`

One thread opens a window with a button, and another prints to the console every 2 seconds. Each has a separate main context and main loop. When the button in the first thread is pushed, the other thread's event loop data structures are manipulated to schedule the running of idle_callback() when possible in the other thread. */

#include <glib.h>
#include <gtk/gtk.h>

GMainContext *thread1_context, *thread2_context;

gboolean timeout_callback(gpointer data)
{
g_print("timeout_callback()\n");
return TRUE;
}

gboolean idle_callback(gpointer data)
{
g_print("idle_callback()\n");
return FALSE;
}

gpointer thread2_entry(gpointer data)
{
GMainLoop *main_loop;
GSource *seconds_timeout_source;

main_loop = g_main_loop_new(thread2_context, FALSE);

seconds_timeout_source = g_timeout_source_new_seconds(2);
g_source_set_callback(seconds_timeout_source, timeout_callback, NULL, NULL);
g_source_attach(seconds_timeout_source, thread2_context);

g_main_loop_run(main_loop);
}

void button_click(GtkWidget *widget, gpointer data)
{
GSource *idle_source;

idle_source = g_idle_source_new();
g_source_set_callback(idle_source, idle_callback, NULL, NULL);
g_source_attach(idle_source, thread2_context);
}

gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
return FALSE;
}

void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}

int main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget *button;

gtk_init(&argc, &argv);
g_thread_init(NULL);

thread1_context = g_main_context_default();
thread2_context = g_main_context_new();

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

g_signal_connect(G_OBJECT(window), "delete_event",
                       G_CALLBACK(delete_event), NULL);

g_signal_connect(G_OBJECT(window), "destroy",
                      G_CALLBACK(destroy), NULL);

gtk_container_set_border_width(GTK_CONTAINER(window), 10);

button = gtk_button_new_with_label("Test");

g_signal_connect(G_OBJECT(button), "clicked",
                       G_CALLBACK(button_click), NULL);
gtk_container_add(GTK_CONTAINER(window), button);

gtk_widget_show_all(window);

g_thread_create(thread2_entry, NULL, FALSE, NULL);

gtk_main();
return 0;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]