GTK3.0 + App UI проблемы с заморозкой. Проблемы с потоками - PullRequest
0 голосов
/ 21 февраля 2020

Я делаю небольшой проект в C и использую GTK для пользовательского интерфейса. У меня проблема с зависаниями и исключениями, которые, как я предполагаю, вызваны тем, как мое приложение использует потоки. Мне нужно было остановить приложение (такие функции, как PlayersTurn (), leftBotsTurn ()), чтобы дождаться пользовательского ввода (используется while (var); loop, var устанавливается в false после того, как пользователь нажимает любую кнопку.) Для этого В целях я начал использовать потоки, потому что если вы не позволите оконной функции завершиться sh, она не будет рисовать окно.

Так что есть несколько функций:

Main :

int main (int    argc,  char **argv){
  openMenu(argc, argv);
  return 0;}

openMenu


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();
}

newGame

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);
    }

Игра л oop

    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)

Может кто-нибудь помочь мне решить эту проблему ??

1 Ответ

1 голос
/ 24 февраля 2020

Для инициализации поддержки одновременных потоков вызовите XInitThreads (); до gtk_init ();

вы можете обновить gui только из основного потока. Чтобы вызвать изменения из другого потока, вы должны вызвать 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

, это обеспечит вам лучшее удаление текста основной л oop (https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html)

...