使用GTK和C,如何使用按鈕啓動/停止長計算(在單獨的線程中)?我的工作代碼就是這樣做的,但我對這是一個合理的方法(即「正確的」)沒有多少信心。使用GTK和C,如何使用按鈕啓動/停止長計算(在單獨的線程中)?
我有一個按鈕,其標籤切換從「開始」「停止」。我也有一個全局pthread_t變量來存儲一個線程。我的方法是通過按鈕的單擊信號處理程序啓動或取消線程,具體取決於全局布爾類型的「空閒」標誌的值,該標誌指示線程當前是否正在運行。
我想工作精心設計的最小測試用例,這樣我可以很容易地理解代碼爲更大的計劃相適應。這個問題與Python&PyGTK: Stop while on button click非常相似,但是這個問題在Python中我不知道。
我的代碼---貼在下面 - 似乎工作,但我不相信它,因爲我可以很容易地只需點擊開始使系統癱瘓/停止按鈕幾次快速連續。
我很好奇,看看別人怎麼會(獨立)解決這個問題,怎麼他們的做法比較雷,也是一個代碼審查我自己的方法,如果它實際上是一個體面的方式。
#include <gtk/gtk.h>
#include <pthread.h>
/* suppress unused variable warnings */
#define UNUSED(x) (void)(x)
typedef struct _Data {
GtkWidget *window1,
*button1;
gint idle;
pthread_t calcthread;
} Data;
static Data *data;
void *calcfunc(void *arg) {
int i;
UNUSED(arg);
data->idle=FALSE;
gtk_button_set_label(GTK_BUTTON(data->button1),"Stop");
/* This is intended to simulated a long calculation that may finish.
Adjust the limit as needed */
for(i=1;i<2e9;++i) {
}
data->idle=TRUE;
pthread_exit(NULL);
}
/* this is our click event handler.... it suppose to start or stop
the "calcthread" depending on the value of the "idle" flag */
void on_button1_clicked(GtkWidget *widget, Data *ldata) {
int ret;
UNUSED(widget);
UNUSED(ldata);
if (data->idle==TRUE) {
printf("idle.. starting thread\n");
ret=pthread_create(&data->calcthread, NULL, calcfunc, NULL);
if (ret !=0) {
g_error("ERROR: could not create thread\n");
}
} else {
printf("not idle... canceling thread...");
ret= pthread_cancel(data->calcthread);
if (ret != 0) {
g_error("ERROR: could not cancel thread\n");
} else {
printf("canceled\n");
}
data->idle=TRUE;
gtk_button_set_label(GTK_BUTTON(data->button1),"start");
}
}
/* just defines our setup */
int main (int argc, char *argv[]) {
g_thread_init(NULL);
gdk_threads_init();
gdk_threads_enter();
gtk_init(&argc, &argv);
data=g_slice_new0(Data);
data->idle=TRUE; /* initial state */
printf("idle is %d\n",data->idle);
/* add widgets and objects to our structure */
data->window1=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(data->window1),250,250);
data->button1=gtk_button_new_with_label("Start");
gtk_container_add(GTK_CONTAINER(data->window1),GTK_WIDGET(data->button1));
gtk_signal_connect(GTK_OBJECT(data->window1), "delete-event",
gtk_main_quit, NULL);
gtk_signal_connect(GTK_OBJECT(data->button1), "clicked",
G_CALLBACK(on_button1_clicked), NULL);
gtk_widget_show_all(GTK_WIDGET(data->window1));
gtk_main();
/* Don't forget to free the memory! */
g_slice_free(Data, data);
gdk_threads_leave();
return 0;
}
這裏有一些競爭條件,例如,你的回調檢查空閒標誌併產生線程,但是在那時,回調可以再次運行並且在calcfunc有機會運行之前檢查空閒(調度器被允許按照線程執行的順序做任何事情),然後你已經產生了兩個線程,但不再有第一個線程的句柄。控制器線程跟蹤空閒/運行可能會更好。 – engineerC 2013-03-25 23:14:54