RE: What is the minimum number of lines to update a gui window without user clicking a button



Quoth L. D. James:
     // The final step is to display this newly created widget...
     m_textview.show();
     Glib::Thread::create(sigc::mem_fun(*this, &HelloWorld::cpp_app),
true); }
[...]
void HelloWorld::cpp_app()
{
     string texttoprint = "";
     Glib::RefPtr<Gtk::TextBuffer> m_refTextBuffer;
     m_refTextBuffer = Gtk::TextBuffer::create();

     texttoprint +=
             "About to run a number of c++ functions\nand display the
results\n";
     m_refTextBuffer->set_text(texttoprint);
     m_textview.set_buffer(m_refTextBuffer);

This is all fine right up until that last line, which contains a subtle (but
important) bug.

GTK widgets (and other UI elements of most other GUI frameworks) are
typically not merely thread-unsafe (as most objects are by default: can be
called from any thread provided that they can be guaranteed to not be called
concurrently) but actually thread-bound (can be called only from one
specific thread, typically the one that created them, or a designated "main
thread").

It is therefore not permitted to touch m_textview from any thread other than
the main thread, which that last line is doing.  (And then since this is
assigning a reference to the buffer, it then becomes unsafe to further
modify that buffer later in the worker thread.)

In short, while this might appear to work on your machine for this contrived
example, if you run it enough times in enough different environments and
with different workloads (eg. more frequent text updates) it's very likely
to either crash or exhibit other strange behaviour.  So don't do that.

Others have already pointed you at the correct solutions, and as I am not
sufficiently practiced at GTK myself to give you a precise example I can
only reiterate what those others have said.

From your description of what you're trying to do it seems likely that
carrying out the "actual work" on a separate thread is indeed the correct
thing to be doing.  But you can't just play with GUI objects outside of the
GUI thread.  You need to use some method to convey data from one thread to
another (eg. an explicitly thread-safe queue) combined with some way to get
the main thread to wake up and do some processing (eg. Glib::Dispatcher or a
timeout handler).

In your case, I would recommend using a std::queue of text-to-be-added
protected by a mutex (to make it thread-safe) combined with a
Glib::Dispatcher callback that triggers the main thread to dequeue text and
add it to the textview.

(Though again as others have pointed out if your "actual work" is merely
calling a console application or performing file/network/pipe I/O then you
may want to try using the asynchronous I/O helpers instead, to avoid the
extra thread.)

Multithreading is hard (to get correctly, at least -- it's easy to do it
wrong).  Asynchronous is less hard but still confusing until you get used to
the ideas.  It may be worthwhile for you to read up on both of these
concepts independently of GTK, then read how they apply to GTK, then finally
how they apply to your applications.  You're not going to find a quick and
easy solution -- or at least if you do find one and try to use it without
properly understanding it, you're letting yourself in for a world of hurt.




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]