"That" question about threads and updating to the GUI, again

A friend who is just starting out writing a GUI app in Python
mentioned he was having problems with his app crashing now & then. He
also said he is using threads in that app.

I told him he needs to make sure that updates to the GUI must be done
in the same thread which that created the GUI, or else he is likely to
have problems.

When he asked what the reason was, I didn't know the reason for this.

I would like to know the underlying technical reason why GUI updates
must be done from the same thread the GUI was created in.

My friend is using pyQt/QT, so this can't just be an issue with
wxWidgets.

I don't understand how the "threadedness" of a Python app could be
felt in a C++ layer, since the thread context exists in the Python
interpreter.

I've looked online for some explanation of this but haven't found one,
so if someone would point me to some resources which explain this, it
would be helpful.

Along with all of this, why is it that wx isn't "thread safe" (better
yet, why aren't gui frameworks designed to be thread safe)?

Hi,

A friend who is just starting out writing a GUI app in Python
mentioned he was having problems with his app crashing now & then. He
also said he is using threads in that app.

I told him he needs to make sure that updates to the GUI must be done
in the same thread which that created the GUI, or else he is likely to
have problems.

When he asked what the reason was, I didn't know the reason for this.

I would like to know the underlying technical reason why GUI updates
must be done from the same thread the GUI was created in.

Because there are no guards against what the UI framework might be doing to the memory owned by the objects in its thread when you try to modify the same memory from a second thread.

For example:

1) A button object has memory allocated to hold its label string
2) MainLoop starts processing a paint event
3) The framework is in the process of redrawing the screen and is at that moment accessing that memory to get the string to draw.
4) If you make a call to modify the label from another thread at this same moment, this will cause an access violation as the memory being accessed by the main thread will get modified while it is being accessed.
5) Crash (quite literally)

My friend is using pyQt/QT, so this can't just be an issue with
wxWidgets.

I don't understand how the "threadedness" of a Python app could be
felt in a C++ layer, since the thread context exists in the Python
interpreter.

Programming language doesn't matter, its a matter of memory access. From the point of the cpu the memory is all the same it doesn't know anything about what language it was written in.

Along with all of this, why is it that wx isn't "thread safe" (better
yet, why aren't gui frameworks designed to be thread safe)?

Its often not needed, adds to design complexity, and adding mutexes/semaphores everywhere would have an affect on performance.

Cody

···

On Jan 31, 2010, at 10:40 PM, cappy2112 wrote:

Its often not needed, adds to design complexity, and adding mutexes/semaphores everywhere would have an affect on performance.

Just an idea, why can’t there be one lock in the wx.MainLoop?

then any Thread could get the lock and play around.

For example:

1) A button object has memory allocated to hold its label string
2) MainLoop starts processing a paint event
3) The framework is in the process of redrawing the screen and is at
that moment accessing that memory to get the string to draw.
4) If you make a call to modify the label from another thread at this
same moment, this will cause an access violation as the memory being
accessed by the main thread will get modified while it is being
accessed.
5) Crash (quite literally)

But python threads are a joke, they areally aren't threads in the
sense of "multiple tasks happening concurrently".
Only one thread is every running at any instance in time, regardless
of the number of processors in the system.
In that sense, only one thread can modify/reference any resource in
the process memory space.

Programming language doesn't matter, its a matter of memory access.
From the point of the cpu the memory is all the same it doesn't know
anything about what language it was written in.

Its often not needed, adds to design complexity, and adding mutexes/
semaphores everywhere would have an affect on performance.

Well, wouldn't you rather have a program that runs a little slower,
than having the potential to always crash?

Hi,

But python threads are a joke, they areally aren’t threads in the
sense of “multiple tasks happening concurrently”.
Only one thread is every running at any instance in time, regardless
of the number of processors in the system.
In that sense, only one thread can modify/reference any resource in
the process memory space.

This isn’t true at all, Python threads are real os level threads. It is true that only one thread can be running inside the interpreters space at one time due to the GIL (with a few exceptions such as threads doing IO), but it does not mean that multiple system calls can’t be happening at the same time. One of main issues with Python threads (performance wise) isn’t so much the GIL though as it that Python does not really do any of its own thread scheduling and just lets the OS do it. There are some interesting talks about this subject floating about the web if you search a little.

Its often not needed, adds to design complexity, and adding mutexes/
semaphores everywhere would have an affect on performance.

Well, wouldn’t you rather have a program that runs a little slower,
than having the potential to always crash?

Well, as you can see from my reply ‘performance’ was the #3 reason I gave. Issues #1 and #2 are far greater in significance than the performance issue.

The main thing is that is just simply not necessary, only one thread at a time can access the shared memory space at anytime anyway so why not just let the main thread do it by posting an event to the event queue and let the normal flow of execution handle it. Also with any sort of locking facility you would need to the implement some sort of lock acquisition algorithm on the calling end. Using optimistic locking would probably be the best approach in this sort of usage, which would mean you would need to have retry loops everywhere and then still have to account for the possibility that you were not able to acquire the lock which would mean you could still crash or end up in a bad state.

Simply put things are not the way they are for no reason.

Cody

···

On Jan 31, 2010, at 11:29 PM, cappy2112 wrote:

That is only true for the Python code itself. Python threads are the native platform threads, and when control transitions from Python to C/C++ code the GIL is released. This allows other Python threads to run at the same time that the C/C++ code in the original thread is running. When the C/C++ code completes then the GIL is reacquired and control returns to the Python code in the original thread as soon as it is able to. This means that it is entirely possible for multiple threads to execute the native UI code at the same time.

There are additional constraints on UI code that you would run into even if you were using C/C++ without Python. For example on Windows object handles tend to belong to the thread that creates them, and depending on the type of object and operation it may be illegal to access it from another thread. Or it simply may not receive any messages except from the thread that created it, which means that there would be no events for that object dispatched by MainLoop if the object was created in another thread. On GTK you can get serious errors if responses from the X11 server arrive in a different order than the requests were sent, which can easily happen if more than one thread is doing UI operations. These (and other) constraints must be dealt with by any toolkit built on top of the native UI toolkits, and the way that wx has dealt with it is to simply stipulate that all UI access should be done from the UI thread.

···

On 1/31/10 9:29 PM, cappy2112 wrote:

For example:

1) A button object has memory allocated to hold its label string
2) MainLoop starts processing a paint event
3) The framework is in the process of redrawing the screen and is at
that moment accessing that memory to get the string to draw.
4) If you make a call to modify the label from another thread at this
same moment, this will cause an access violation as the memory being
accessed by the main thread will get modified while it is being
accessed.
5) Crash (quite literally)

But python threads are a joke, they areally aren't threads in the
sense of "multiple tasks happening concurrently".
Only one thread is every running at any instance in time, regardless
of the number of processors in the system.
In that sense, only one thread can modify/reference any resource in
the process memory space.

--
Robin Dunn
Software Craftsman

Very interesting!

Simply put things are not the way they are for no reason.

I understand that things just don't happen for a no reason, but until
your reply I didn't know
what some of those reasons were. I've been trying to understand why
Python threads need to use the OS thread APIs at all,
now I know why.

Thanks!