Gtkmm/Glibmm Thread Example

September 30, 2008

After dealing with threads in Qt and seeing how nice and simple it was, I decided to try again with the Gtkmm/Glibmm threading system. I think the crucial piece for me with the Qt threads was the excellent documentation, so I’m going to show you my full example here and document it in detail. As a quick disclaimer, I do not know if this is the 100% “right” way to do threads, but it matches up with everything I’ve read and, more importantly, it works.

Where to start…
I’m going to start with a brief description of what is going to happen. We will develop a threaded worker class, a trivial Gtk::Window class and a trivial main function. Let’s get the first two out of the way early, since they are the easy ones.

int main ()

This is a pretty standard main function, with one notable nod to Glibmm, and that is line 84.

You only ever call Glib::thread_init(); once, otherwise it will abort with an error. So what we are doing is asking Glib “Are you already handling threads?” and if it isn’t we initialize the threading system. This has the additional perk of aborting the program if threads are not supported at all.

If the rest of this function doesn’t make sense to you, walk away from this tutorial and go read the Gtkmm one.

MyWindow
Next we are going to implement that Gtk::Window class that we use in main, ever so imaginatively called MyWindow. There is nothing much special going on, so I’ll show you the full listing then pick out the important bits.

As you can tell, this is a simple Gtk::Window with just a single button (thrashHive) in it. In the constructor we connect this button to a method go() at line 52. go() is important to us because it is where we create and launch our thread, which is represented as the class Worker of which we have a pointer declared at line 78 called bee. Let’s run through go() line by line.

In lines 58 and 59 we are protecting our memory from trying to create multiple instances of a Worker thread, a good idea to stay safe in an asynchronous environment.

At line 61 we instantiate a new Worker class. Next at line 62 we connect the signal sig_done to our beeDone() method, which essentially just undoes everything we do in go(). We do this because this is a non-blocking, asynchronous working thread and we need to know when it is finished running. When we get to the implementation of the Worker class, you’ll see that this “signal” is not a given, but rather something we implement ourselves, and we can have as many “signals” for events as needed. Lastly we start our thread at line 63.

Here we disable our button and change it’s text. Why do this here and not before thread creation? In most cases that would be a good idea, but here we want to demonstrate that the main thread is still working, so we do updates to the GUI after we start the worker thread.

Worker
The Worker class is actually fairly simple. It has a basic set of steps:

  1. Create and wait to be started.
  2. Get started, create thread and run.
  3. Do work, emit signals, check for being aborted.
  4. Return when done, then wait around until cleaned up.

Just breeze over the full listing then we’ll go over each of those points one at a time.

We don’t have anything to deal with for the first point. In the constructor we just initialize the Glib::Thread to 0 and our sentinel boolean, stop to false.

For the second point, we need to look at start() and run().

start() is our public method, and it creates and runs the actual Glib::Thread. Doing that is fairly straight forward:

The run() method is where our blocking operations go so that we don’t have to worry about gumming up the UI, this is where the work actually happens (i.e. step 3).

In my run() I just wait five seconds and write to stdout, but if you are doing a lengthy process, you should occasionally check the stop variable for an abort condition by using lines 30 – 33. Always put your Glib::Mutex::Lock inside of their own block, it is easier to handle them that way as the destructor does the cleanup work for you.

On line 37 we see a “signal” being emitted. This is actually a Glib::Dispatcher, which uses pipes for asynchronous communication between threads. In practical application just treat it like a sigc::signal . If you need to communicate data, emit the Glib::Dispatcher and have the receiving thread do method calls to get the information from stored values in the sending thread.

One easy to miss caveat when using gthreads, you have to throw in some extra libraries with pkg-config --libs gthread-2.0, here is the command line to compile this demo application.

That is the guts of a simple Gtkmm/Glibmm worker thread, I hope that I was clear if not concise. Here is the complete listing of the program for your reading/borrowing/compiling pleasure.

Categories: Geek
Tags: , , , ,

Comments

  1. KYRM& says:

    Nice!!

    Very usefull… thanks!

    =)

  2. ilkapo says:

    Great tutorial, very good work!

    :)

  3. john says:

    Wow, thanks! I’ve actually used your site for reference on some Cairo work before :-)

  4. Tom says:

    Thanks for the tutorial! In line 11, you reference WgetWorker but this should instead be Worker.

  5. john says:

    Thanks Tom, glad to be useful! I’ll fix that.

  6. Sven says:

    Thanks for the Example. Very very very useful.

  7. Antanas says:

    thank you so much! at last solved my problem after two sleepless nights :)

  8. Jacky Alcine says:

    YOU are a GODSEND.

    I’m going to link this and flesh it out for a possible class to make synchronous and asynchronous threads.

    Thank you again.

  9. john says:

    Hey Jacky –

    Glad it helps. If you have any updates or end up writing a wrapper lib, please share!

  10. virgoptrex says:

    nice example. I was wondering if there was a way to use a smart pointer in your example instead of “new” and “delete”.

  11. John Hobbs says:

    I’m not sure, I’ve not done any C++ in quite a while. It seems like adding complexity though, as the smart pointer would just call new and delete and ref count on it.

  12. João André says:

    Very useful tutorial. I’m sorry to be ressucting this though, but is there such a thing as a sig_done() version for a timeout signal, or would I need to wrap the thread manipulation with a timeout signal callon the Gtk::Window side? I am trying to have the thread processing continue until I hit a “stop” button.

  13. Jean says:

    Still very useful, thx :)

Leave A Comment

Your email will not be published.