Gtk multithreading issue

Dear Community,
I am using GTK+3.0 in a embedded microprocessor. Our application mainly uses graph (Slope Graph) for displaying data from two sensors as a graph. We have implemented this as below.
1.A thread (running infinite while loop) is created from GTK app for acquiring real time data from sensors.
2.For updating the slope graph, I am using g_timeout_add function with 0 as time interval.
3.Inside the created thread, there will be a infinite while loop that will be getting data from sensors and it will plot the graph only when a start condition occurs and continue to plot till the stop condition occurs.

I am attaching the implementation here.

While doing so, The application gets crashed as the realloc of two array and plotting graph with those arrays seems to be happening at the same time.
I tried to add mutex lock and unlock for realloc part and also for the graph update part (inside g_timeout_add() ) but a dead lock is happening.

Is the above designed implementation correct? If not, Kindly help me with your ideas and suggestions.

Note: The array used here are global.
Also I am assuming that the app crash is because the g_timeout_add is not happening sequentially with the thread(it is behaving parallel like a new thread). The problem might be corrected if it works sequentially inside the thread.Is my assumption right?

Thanks for your time.
Regards,
Nishanth

2 Likes

In other words you are using an idle function: just use g_idle_add or (even better) g_main_context_invoke.

As you have experienced, you cannot freely read, write and especially realloc/free memory shared across concurrent threads. There are many ways to solve your problem, e.g. by not reallocating and protecting the access with mutexes or passing a new buffer to the idle function (and letting the idle function free it when done).

IMO, the simplest and quickest way in your use case would be the second option, i.e. do not use globals and pass a duplicate of the arrays to your idle function (or, equivalent, use alloc once instead of realloc after the idle function has been called) and free them there.

1 Like

Dear Nicola Fontana,
Thanks for your reply and suggestions. In my case, the arrays will be of huge size ie) around 4000000 double values in maximum. So I think it would be inappropriate to have this size in the memory always. Will try your suggestions and get back to you. Also, in the meanwhile can we make while(1) wait until the g_timeout_add is completed ie) as sequentially?

Thanks and Regards,
Nishanth

This is what mutexes are intended for, e.g.:

static gpointer my_data = NULL;
G_LOCK_DEFINE(my_data);

static gboolean my_idle_callback()
{
    /* ... do something with my_data ... */
    G_UNLOCK(my_data);
    return G_SOURCE_REMOVE;
}

static gpointer my_thread()
{
    /* ... */
    while (1) {
        /* This will block until the mutex is released */
        G_LOCK(my_data);

        /* ... populate my_data ... */

        /* Do not unlock: it is my_idle_callback responsibility! */
        g_main_context_invoke(NULL, my_idle_callback, NULL);
    }
    /* ... */
}
2 Likes

Hi,Nicola Fontana,
Instead of G_LOCK, I am using a normal C mutex locking and unlocking and my code is working very fine but after some time it gets crashed. Also I am just using g_timeout_add for drawing graph. What will be the reason for the crashing because now my code is running sequentially only?

Thanks for your time.
Regards,
Nishanth

True, but it’s not that simple. Unlocking a mutex that is not locked by the current thread leads to undefined behavior. You’d need to use a GCond to synchronize the threads.

1 Like

Yes, you are absolutely right: I just checked the pthread_mutex_lock manpage.

You can also use the mutex in the right way, e.g.:

static gboolean my_idle_callback()
{
    G_LOCK(my_data);
    /* ... */
    G_UNLOCK(my_data);
    return G_SOURCE_REMOVE;
}

while (1) {
    G_LOCK(my_data);
    /* ... */
    G_UNLOCK(my_data);
    g_main_context_invoke(NULL, my_idle_callback, NULL);
}

This can potentially queue more than one idle callback.