GTK3.0+ App UI 冻结问题。线程问题
GTK3.0+ App UI freeze problems. Threading problems
我正在用 C 编写一个小项目并使用 GTK UI。我遇到冻结和异常问题,我认为这是由我的应用程序使用线程的方式触发的。
我需要停止应用程序(playersTurn()、leftBotsTurn() 等函数),以等待用户输入(使用 while(var); 循环,在用户单击任何按钮后将 var 设置为 false。) 为此目的我开始使用线程,因为如果你不让 window 函数完成它就不会绘制 window.
所以功能很少:
主要:
int main (int argc, char **argv){
openMenu(argc, argv);
return 0;}
打开菜单
static void openMenu(int argc, char *argv[]){
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("menu_window_glade.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "menu_window"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(window);
gtk_main();
}
新游戏
void newGame(){
GtkBuilder *builder;
GtkWidget *window;
widgetsPtrs *widgets = (widgetsPtrs *) malloc(sizeof(widgetsPtrs));
builder = gtk_builder_new_from_file("game_glade.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "game_glade_window"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(window);
/* Getting PlayersHand, AttackingRow, DefendingRow,TrumpImage pointers. */
for(int i = 0; i < 20; i++){
//The code is hidden, but all it does is uses gtk_builder_get_object and saves pointers
//in "widgets"
}
//g_mutex_init(myMutex); Tried to use mutex, but I couldn't find any example of g_mutex.
GThread *thread;
thread = g_thread_new("gameLoop", gameLoop, widgets);
}
游戏循环
void *gameLoop(void *value){
widgetsPtrs *widgets = (widgetsPtrs *)value;
cardsOnTheTable = malloc(sizeof(card));
cardsOnTheTable->next = NULL;
shuffleTheDeck();//allocates a card for the Deck. Shuffles it, makes a SLL out of it.
player = malloc(sizeof(card));
leftBot = malloc(sizeof(card));
rightBot = malloc(sizeof(card));
player->next = NULL;
leftBot->next = NULL;
rightBot->next = NULL;
deal(player);
deal(leftBot);
deal(rightBot);
printPlayersCards(player, leftBot, rightBot);
//g_mutex_lock(myMutex);
//Setting trump image.
card *tmpTrumpCard = getTheLastCard(Deck);
setCardImage(tmpTrumpCard, GTK_IMAGE(widgets->w_trumpImagePtr));
//g_mutex_lock(myMutex);
int a = firstTurnCheck();
int turnResult = 0;
while((Deck->next != NULL) || ((player->next != NULL) && ((leftBot->next != NULL) || (rightBot->next != NULL)) ) ){
//g_mutex_lock(myMutex);
showPlayerCards(widgets);
sleep(1);
if((a % 3) == 0){
puts("PlayersTurn. //GameLoop");
turnResult = playersTurn(widgets);
if(turnResult == 1){
a = 1;
}else{
a = 2;
}
}else if((a % 3) == 1){
puts("LeftbotsTurn. //GameLoop");
turnResult = leftBotsTurn(widgets);
if(turnResult == 1){
a = 2;
}else{
a = 0;
}
}else if((a%3) == 2){
puts("RightbotsTurn. //GameLoop");
turnResult = rightBotsTurn(widgets);
if(turnResult == 1){
a = 0;
}else{
a = 1;
}
}
hidePlayerCards(widgets);
deal(player);
deal(leftBot);
deal(rightBot);
clearTheTable(widgets);
printPlayersCards(player, leftBot, rightBot);
cardsOnTheTable->next = NULL;
//g_mutex_unlock(myMutex);
sleep(1);
}
// while((Deck->next != NULL) || (player->next != NULL && leftBot->next != NULL) || (player->next != NULL && rightBot->next != NULL)){
// gtk_widget_set_sensitive((widgets->w_buttons[2]), true);
// if(a == 0){
// }else if(a == 1){
// }else if(a == 2){
// }
// }
if(player->next == NULL){
puts("You won!");
}else{
puts("Jokes on you. ");
}
//pthread_exit(NULL);
free(player);
free(leftBot);
free(rightBot);
free(Deck);
free(widgets);
free(cardsOnTheTable);
return NULL;}
错误
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
main: ../../src/xcb_io.c:165: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted (core dumped)
谁能帮我解决这个问题??
初始化对并发线程的支持
调用 XInitThreads();在 gtk_init();
之前
您只能从主线程更新图形用户界面。要从不同的线程调用更改,您必须调用 g_idle_add().
#include <gtk/gtk.h>
int counter = 0;
void idleLoop(gpointer data) {
char *yolo = g_strdup_printf("counting ... %d", counter);
gtk_label_set_text(GTK_LABEL(data), yolo);
g_free(yolo);
}
void *gameLoop(gpointer data) {
printf("starting loop \n");
while (1) {
counter++;
/*
#IMPO# putting the ui update command here wont work
char *yolo = g_strdup_printf("counting ... %d", counter);
gtk_label_set_text(GTK_LABEL(data), yolo);
g_free(yolo);
*/
g_usleep(5000);
g_idle_add(idleLoop, data);
}
return NULL;
}
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Window");
gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
GtkWidget *label = gtk_label_new(
"<big>This is a long text that might need to be wrapped</big>");
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
g_object_set(label, "margin", 20, NULL);
gtk_container_add(GTK_CONTAINER(win), label);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(label), 30);
g_signal_connect(GTK_WIDGET(win), "destroy", gtk_main_quit, NULL);
gtk_widget_show_all(GTK_WIDGET(win));
g_thread_new("gameLoop", gameLoop, label);
gtk_main();
}
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-idle-add
这将使您更好地取消主循环 (https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html)
我正在用 C 编写一个小项目并使用 GTK UI。我遇到冻结和异常问题,我认为这是由我的应用程序使用线程的方式触发的。 我需要停止应用程序(playersTurn()、leftBotsTurn() 等函数),以等待用户输入(使用 while(var); 循环,在用户单击任何按钮后将 var 设置为 false。) 为此目的我开始使用线程,因为如果你不让 window 函数完成它就不会绘制 window.
所以功能很少:
主要:
int main (int argc, char **argv){
openMenu(argc, argv);
return 0;}
打开菜单
static void openMenu(int argc, char *argv[]){
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("menu_window_glade.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "menu_window"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(window);
gtk_main();
}
新游戏
void newGame(){
GtkBuilder *builder;
GtkWidget *window;
widgetsPtrs *widgets = (widgetsPtrs *) malloc(sizeof(widgetsPtrs));
builder = gtk_builder_new_from_file("game_glade.glade");
window = GTK_WIDGET(gtk_builder_get_object(builder, "game_glade_window"));
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(window);
/* Getting PlayersHand, AttackingRow, DefendingRow,TrumpImage pointers. */
for(int i = 0; i < 20; i++){
//The code is hidden, but all it does is uses gtk_builder_get_object and saves pointers
//in "widgets"
}
//g_mutex_init(myMutex); Tried to use mutex, but I couldn't find any example of g_mutex.
GThread *thread;
thread = g_thread_new("gameLoop", gameLoop, widgets);
}
游戏循环
void *gameLoop(void *value){
widgetsPtrs *widgets = (widgetsPtrs *)value;
cardsOnTheTable = malloc(sizeof(card));
cardsOnTheTable->next = NULL;
shuffleTheDeck();//allocates a card for the Deck. Shuffles it, makes a SLL out of it.
player = malloc(sizeof(card));
leftBot = malloc(sizeof(card));
rightBot = malloc(sizeof(card));
player->next = NULL;
leftBot->next = NULL;
rightBot->next = NULL;
deal(player);
deal(leftBot);
deal(rightBot);
printPlayersCards(player, leftBot, rightBot);
//g_mutex_lock(myMutex);
//Setting trump image.
card *tmpTrumpCard = getTheLastCard(Deck);
setCardImage(tmpTrumpCard, GTK_IMAGE(widgets->w_trumpImagePtr));
//g_mutex_lock(myMutex);
int a = firstTurnCheck();
int turnResult = 0;
while((Deck->next != NULL) || ((player->next != NULL) && ((leftBot->next != NULL) || (rightBot->next != NULL)) ) ){
//g_mutex_lock(myMutex);
showPlayerCards(widgets);
sleep(1);
if((a % 3) == 0){
puts("PlayersTurn. //GameLoop");
turnResult = playersTurn(widgets);
if(turnResult == 1){
a = 1;
}else{
a = 2;
}
}else if((a % 3) == 1){
puts("LeftbotsTurn. //GameLoop");
turnResult = leftBotsTurn(widgets);
if(turnResult == 1){
a = 2;
}else{
a = 0;
}
}else if((a%3) == 2){
puts("RightbotsTurn. //GameLoop");
turnResult = rightBotsTurn(widgets);
if(turnResult == 1){
a = 0;
}else{
a = 1;
}
}
hidePlayerCards(widgets);
deal(player);
deal(leftBot);
deal(rightBot);
clearTheTable(widgets);
printPlayersCards(player, leftBot, rightBot);
cardsOnTheTable->next = NULL;
//g_mutex_unlock(myMutex);
sleep(1);
}
// while((Deck->next != NULL) || (player->next != NULL && leftBot->next != NULL) || (player->next != NULL && rightBot->next != NULL)){
// gtk_widget_set_sensitive((widgets->w_buttons[2]), true);
// if(a == 0){
// }else if(a == 1){
// }else if(a == 2){
// }
// }
if(player->next == NULL){
puts("You won!");
}else{
puts("Jokes on you. ");
}
//pthread_exit(NULL);
free(player);
free(leftBot);
free(rightBot);
free(Deck);
free(widgets);
free(cardsOnTheTable);
return NULL;}
错误
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
main: ../../src/xcb_io.c:165: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted (core dumped)
谁能帮我解决这个问题??
初始化对并发线程的支持 调用 XInitThreads();在 gtk_init();
之前您只能从主线程更新图形用户界面。要从不同的线程调用更改,您必须调用 g_idle_add().
#include <gtk/gtk.h>
int counter = 0;
void idleLoop(gpointer data) {
char *yolo = g_strdup_printf("counting ... %d", counter);
gtk_label_set_text(GTK_LABEL(data), yolo);
g_free(yolo);
}
void *gameLoop(gpointer data) {
printf("starting loop \n");
while (1) {
counter++;
/*
#IMPO# putting the ui update command here wont work
char *yolo = g_strdup_printf("counting ... %d", counter);
gtk_label_set_text(GTK_LABEL(data), yolo);
g_free(yolo);
*/
g_usleep(5000);
g_idle_add(idleLoop, data);
}
return NULL;
}
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Window");
gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
GtkWidget *label = gtk_label_new(
"<big>This is a long text that might need to be wrapped</big>");
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
g_object_set(label, "margin", 20, NULL);
gtk_container_add(GTK_CONTAINER(win), label);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_label_set_max_width_chars(GTK_LABEL(label), 30);
g_signal_connect(GTK_WIDGET(win), "destroy", gtk_main_quit, NULL);
gtk_widget_show_all(GTK_WIDGET(win));
g_thread_new("gameLoop", gameLoop, label);
gtk_main();
}
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-idle-add
这将使您更好地取消主循环 (https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html)