Sergio6Rey
Sergio6Rey

Reputation: 403

How to cancel a thread from another thread (Glib threads)?

I am developing an application library using GTK and the functions for threads in GLib. I have a thread (from now on will be called thread A) that is created when I hit an "ok" button in a certain graphical window. Thread A starts doing some heavy tasks. Another button named "cancel" is available to stop and finish thread A at any moment.

My aim is to code a function for the thread created when I hit the "cancel" button (thread B) that has the ability to end the thread A.

I create thread A with the function g_thread_create. However I cannot find any function similar to g_thread_cancel to stop thread A using thread B. Is this possible or cannot be done?

Thank you so much for any kind of information provided.

Upvotes: 1

Views: 1385

Answers (2)

Sergio6Rey
Sergio6Rey

Reputation: 403

I have developed a code that is able to cancel a thread from another, both of them created from a main one. The code works correctly according to my tests:

#include <pthread.h>
#include <stdio.h>

    /* these variables are references to the first and second threads */
    pthread_t inc_x_thread, inc_y_thread;

/* this function is run by the first thread */
void *inc_x(void *x_void_ptr)
{

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

    /* increment x to 100 */
    int *x_ptr = (int *)x_void_ptr;



    while(++(*x_ptr) < 100000000);


    printf("x increment finished\n");

    /* the function must return something - NULL will do */
    return NULL;
}

/* this function is run by the second thread */
void *inc_y(void *x_void_ptr)
{

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

    /* increment y to 100 */
    int *x_ptr = (int *)x_void_ptr;

    pthread_cancel(inc_x_thread);

    while(++(*x_ptr) < 100);

    printf("y increment finished\n");

    return NULL;
}

/* this is the main thread */
int main()
{

    int x = 0, y = 0;
    void *res;

    /* show the initial values of x and y */
    printf("x: %d, y: %d\n", x, y);

    /* create a first thread */
    if(pthread_create(&inc_x_thread, NULL, inc_x, &x)) {
        fprintf(stderr, "Error creating thread\n");
        return 1;
    }

    /* create a second thread */
    if(pthread_create(&inc_y_thread, NULL, inc_y, &y)) {
        fprintf(stderr, "Error creating thread\n");
        return 1;
    }

    /* wait for the first thread to finish */
    if(pthread_join(inc_x_thread, &res)) {
        fprintf(stderr, "Error joining thread\n");
        return 2;
    }

           if (res == PTHREAD_CANCELED)
               printf(" thread was canceled\n");
           else
               printf(" thread wasn't canceled\n");

    /* wait for the second thread to finish */
    if(pthread_join(inc_y_thread, &res)) {
        fprintf(stderr, "Error joining thread\n");
        return 2;
    }

           if (res == PTHREAD_CANCELED)
               printf(" thread was canceled\n");
           else
               printf(" thread wasn't canceled\n");

    /* show the results*/
    printf("x: %d, y: %d\n", x, y);

    return 0;
}

You can compile the code by using: gcc example.c -lpthread

However, as OznOg and Philip Withnall have said, this is not the correct way of cancelling a thread. It is only a quick way of doing it that might not work in some specific situations. A better and safer way is to gently ask the thread to stop itself.

Upvotes: 0

Philip Withnall
Philip Withnall

Reputation: 5733

You might want to consider using GTask to run your task in a thread, rather than using a manually-created thread. If you use g_task_run_in_thread(), the operation will run in a separate thread automatically.

GTask is integrated with GCancellable, so to cancel the operation you would call g_cancellable_cancel() in the callback from your ‘Cancel’ button.

As OznOg says, you should treat the GCancellable as a way of gently (and thread-safely) telling your task that it should cancel. Depending on how your long-running task is written, you could either check g_cancellable_is_cancelled() once per loop iteration, or you could add the GSource from g_cancellable_source_new() to a poll loop in your task.

The advice about using threads with GLib is probably also relevant here.

Upvotes: 3

Related Questions