The first and foremost rule of GTK programming is that everything related to GTK must happen in a single thread, which is the thread that initialised GTK and spins its main loop.
If you have a long running operation, you can use
GTask, which will run a function in a thread and, once the function returns a value or an error, will invoke a callback in the thread that created the
GTask instance. This, typically, means you create a task in response to an event or any other signal; run it; and then update the UI once the task terminates.
Another option, if your long running operation can be broken down into smaller chunks, is to install a source into the main loop, using functions like
g_timeout_add(). This is generally useful if you have a list of things to iterate over, and each iteration is short enough to be executed within the allotted time for a frame—e.g. 16.67msec for a 60 Hz cycle—and you want to update the UI every time you performed an iteration.
Libraries in the GNOME platform typically have asynchronous API for common things like operating on files; IPC; or network operations.