GThread


一個進程(Process)是一個包括有自身執行位址的程式,在一個多工的作業系統中,可以分配CPU時間給每一個進程,CPU在片段時間中執行某個進程,然後下一個時間片段跳至另一個進程去執行,由於轉換速度很快,這使得每個程式像是在同時進行處理一般。

一個執行緒是進程中的一個執行流程,一個進程中可以同時包括多個執行緒,也就是說一個程式中同時可能進行多個不同的子流程,這使得一個程式可以像是同時間 處理多個事務,例如一方面接受網路上的資料,另一方面同時計算資料並顯示結果,一個多執行緒程式可以同時間處理多個子流程。

在GLib中,提供GThread來實現可攜式的執行緒解決方案,以 內 建 Signal 的發射與停止 中的範例來說,當中使用到 pthread,因而只能在 Linux 之類的系統中執行,您可以改寫為使用GThread的方式,例如:
  • gthread_demo.c
#include <gtk/gtk.h>

gpointer signal_thread(gpointer arg) {
int i;
for(i = 0; i < 5; i++) {
g_usleep(1000000); // 暫停一秒
g_signal_emit_by_name(arg, "clicked");
}
}

// 自訂Callback函式
void button_clicked(GtkWidget *button, gpointer data) {
g_print("按鈕按下:%s\n", (char *) data);
}

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

gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "哈囉!GTK+!");

button = gtk_button_new_with_label("按我");
gtk_container_add(GTK_CONTAINER(window), button);

g_signal_connect(GTK_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(GTK_OBJECT(button), "clicked",
G_CALLBACK(button_clicked), "哈囉!按鈕!");

gtk_widget_show(window);
gtk_widget_show(button);

if(!g_thread_supported()) {
g_thread_init(NULL);
}

g_thread_create(signal_thread, button, FALSE, NULL);

gtk_main();

return 0;
}

在使用g_thread_create()函式之前,先使用g_thread_supported()函式檢查一下執行緒系統是否已初始化, signal_thread是自訂的callback函式,所建立的GThread會執行該函式,g_usleep()是用來暫停執行緒之用,單位是微 秒。

為了編譯這個程式,您必須設定gthread-2.0程式庫路徑資訊,可以使用pkg-config取得這個資訊,例如:
pkg-config --libs gthread-2.0

事實上,GThread要在建立GMainLoop下才能使用,Main Loop的目的是等待事件的發生,並呼叫適當的callback函式,在GTK的程式,不用自行建立Main Loop,因為在gtk_init()中已幫您建立,而Main Loop的執行則是在gtk_main()中替您進行。

下面這個範例程式,示範了如何自行建立Main Loop,並建立三個執行緒,其中一個執行緒會執行checking_thread()函式,以檢查另兩個執行緒是否已完成,若已完成則結束Main Loop:
  • gthread_demo.c
#include <gtk/gtk.h>

gboolean thread1_end = FALSE;
gboolean thread2_end = FALSE;

gpointer thread1(gpointer data) {
int i;
for(i = 0; i < 10; i++) {
g_print("Thread1: %s\n", data);
g_usleep(1000000);
}
thread1_end = TRUE;
}

gpointer thread2(gpointer data) {
int i;
for(i = 0; i < 10; i++) {
g_print("Thread2: %s\n", data);
g_usleep(1000000);
}
thread2_end = TRUE;
}

gpointer checking_thread(gpointer mloop) {
while(TRUE) {
if(thread1_end && thread2_end) {
g_main_loop_quit(mloop);
break;
}
g_usleep(1000);
}
}

int main(int argc, char *argv[]) {
GMainLoop *mloop;

if(!g_thread_supported()) {
g_thread_init(NULL);
}

mloop = g_main_loop_new(NULL, FALSE);

g_thread_create(thread1, "Running", FALSE, NULL);
g_thread_create(thread2, "Going", FALSE, NULL);
g_thread_create(checking_thread, mloop, FALSE, NULL);

g_main_loop_run(mloop);

return 0;
}

一個執行的結果如下所示:
Thread1: Running
Thread2: Going
Thread2: Going
Thread1: Running
Thread1: Running
Thread2: Going
Thread2: Going
Thread1: Running
Thread1: Running
Thread2: Going
Thread1: Running
Thread2: Going
Thread2: Going
Thread1: Running
Thread2: Going
Thread1: Running
Thread1: Running
Thread2: Going
Thread1: Running
Thread2: Going