Hi,

There is some documentation in the Wx distribution

http://search.cpan.org/~mdootson/Wx-0.9901/lib/Wx/Thread.pod

Basically, you only get to access the gui in your main thread. None of the wxWidgets synchronisation methods are wrapped - because they simply don't fit with Perl's threading model.

In short, in secondary threads you have Wx::PlThreadEvent to post events back to some event handler window, in your main thread.

If you need to pass complex data structures a common approach would be to serialize / deserialize the information using something like Storable::freeze / Storable::thaw.

Assuming that your total requirement is just to 'tail' a couple of files and update a TextCtrl, this will work functionally. It is an answer to the question, 'how do I pass information back to the main thread in a threaded app.'

Using a Wx::Timer to poll for something periodically is a method I have also used often - you just need to make sure you are polling the most efficient thing. (e.g. accessing and checking a file every 0.5 seconds probably isn't particularly efficient);

If you are looking at a general way to incorporate asynchronous processing or non-blocking processing in your application, then that's a question of a different order that would need a proper understanding of what your application does to give a helpful answer.

Generally, if you are going to use threads, your application needs to be designed with that in mind from the start with a fully developed model for thread creation, destruction, and communication.

From my observation of other projects and comments by the author of the threads module, there seems to be a single model favoured for using threads in Perl in a practical and scalable way.

My interpretation of that would be to create a second thread - a thread manager thread - as soon as possible in your application. For a Wx application, this would certainly be before Wx is loaded.

This second thread creates new worker threads on request to carry out your asynchronous work.

The worker threads pass information back to the main thread using a Thread::Queue. You then need a way in your main thread to collect the information from the queue and create events in Wx.

In prototyping this type of model in the past, I have used a timer to check $queue->dequeue_nb periodically. An interesting alternate possibility would be to use inter-thread signalling to tell the main thread to check the queue.

threads->object(0)->kill('USR1');

Once you have info off the queue, creating an event out of this to handle in your gui is fairly straightforward. When you ask the worker thread to carry out a task, pass in the window id ( $window->GetId ). The worker returns the windowid as part of the message it puts on the queue. So in the main thread queue handler once you have the 'client' window id

my $win = Wx::Window::FindWindowById($id, undef);

.....

$win->AddPendingEvent($somenewevent);

It must be pointed out that some very talented people with actual threaded code in the wild have taken a slightly different approach in the Padre application. The 'start a worker manager early' approach is pretty much the same I understand but there is a different method of passing information to and from threads that actually uses Wx::PlThreadEvent (or did last time I browsed) and consequently loads Wx before creating the worker-manager thread. The other major difference between the Padre implementation and my outline is that the Padre one is working code and mine exists, partially at least, only in my head.

It is conceptually reasonably simple so "all" you need to do is handle thread creation and shutdown in clean way ..........

It is quite a lot of work really when all you want to do is tail a couple of files and update a gui element.

Alternatives to threads for 'asynchronous' processing: -

The first, and not really asynchronous at all, is to use a Wx::Timer as you suggested and carry out checks in the timer event. This can be a good solution and is certainly the simplest. It all depends on how long the code in your timer event handler blocks for and how much resources it consumes.

All other methods I can think of involve using a separate process and only differ in how they implement inter-process communication. A few methods I have used:

Wx::Perl::ProcessStream offers IPC via stdin, stdout and stderr. Whenever I use Wx::Perl::ProcessStream, I always think 'this is ugly'. But it does work and it is relatively simple. For your case you would create a separate process that watches the files and just prints a message to stdout when there is a change. This would create an event in your main application and you respond by updating the TextCtrl. You could even pass the file content on stdout. It really depends on the frequency of updates and size of the content.

Wx::SocketServer can provide socket based events to your main application, so in this case - start a separate process, passing in your server socket as a param. Connect with your separate process and pass info back and forth across the connection.

An extension to this is to use an intermediate 'message broker' process. Mine have been based around IO::Multiplex and just use that as an extension to the basic Wx::SocketServer method to implement a one main process to many helper processes model.

Hope the info is helpful. I think that if you simply create a separate thread at some arbitrary point in your code, then send information back to a window using Wx::PlThreadEvent, it will work perfectly well. It just doesn't scale very well.

Regards

Mark



On 23/06/2011 14:26, m...@roqc.no wrote:
Hello,

We'd like to use threads in one of our Linux GTK Wx GUI's. The purpose
of the thread is to check some text files for changes every 2 seconds.
The changes need to be written back to a WxTextCtrl. I tried using
Wx::MutexGUIEnter and Wx::MutexGuiLeave to block the main thread from
execution while the GUI update is being made, but get the following error.

Error while autoloading 'Wx::MutexGuiEnter' at sqlplus_gui.pl line 594
thread 1

Do the Mutex functions not work in GTK? I see the message on the Wx
website.

"Note that under GTK, no creation of top-level windows is allowed in any
thread but the main one."


Wx::MutexGuiEnter();
$shared_data->{textctrl}->AppendText('abc');
Wx::MutexGuiLeave();

If this doesn't work in GTK, what is the best approach for having a
secondary thread relay the information back to the main thread for
updating?

Or is using Wx::Timer a better approach?

Thanks,
Mike


Reply via email to