PyQt5 QThread Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

Giuseppe Corbelli corbelligiuseppe at mesdan.it
Thu Jul 1 07:54:28 BST 2021


On 7/1/21 4:09 AM, Maurizio Berti wrote:
> Il giorno mer 30 giu 2021 alle ore 16:30 Giuseppe Corbelli 
> <corbelligiuseppe at mesdan.it <mailto:corbelligiuseppe at mesdan.it>> ha scritto:
> 
>     This is the root of all problems. UI (QWidget) subclasses must live in
>     the main thread.
> 
> 
> To be precise, UI elements can only be created in the main thread, read 
> access to their properties is possible but not always reliable (some 
> properties might require more than one "cycle" of the main event loop in 
> order to be applied), while write access is "forbidden" (or, better, not 
> safe), as it usually causes various levels of issues, from incorrect 
> repainting up to possible crashes.

Well, since no synchronization is provided this is no surprise and holds 
true for everything that runs multithreaded.

>     Besides that you usually do NOT subclass QThread [1] but moveToThread()
>     a QObject subclass and communicate with signals and slots.
>     [1] https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
>     <https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong>
> 
> This is a common misconception, caused by some incorrect interpretations 
> of the above post and how QThread actually works (including with PyQt).
> First of all, exactly like python's Thread, QThread is not a "thread", 
> but a wrapper around the operating system thread.
> They are fundamentally identical, as Phil Thompson (the developer of 
> PyQt) himself explained [1].
> 
> The actual thread is created and then started when start() is called, 
> and it's from that thread that run() is actually executed.
> Subclassing QThread and implementing its run() method is perfectly safe 
> and correct, but there are some differences.
> 
> As explained in the related post on woboq [2]:
> 
>     When to subclass and when not to?
> 
>       * If you do not really need an event loop in the thread, you
>         should subclass.
>       * If you need an event loop and handle signals and slots within
>         the thread, you may not need to subclass.
> 
> Note: the second point says "you may *not* need", not "you should not".

Very good point indeed. If you don't need an event loop (so no signals 
delivery) then there's no point in using QThread instead of plain 
threading module but you're absolutely right.

> This is related to the fact that most threading (especially in PyQt) 
> doesn't need to execute its own separate event loop (which is what the 
> default QThread.run() implementation does: creates an event loop and 
> calls its exec()), but we should also consider that subclassing on 
> C++ and python, while conceptually identical, prompts some differences 
> (I won't dwell on this as I don't have enough technical knowledge on the 
> former).
> 
> For most use cases, subclassing QThread and implementing run() in PyQt 
> is perfectly fine, correct and safe.
> In any case (QThread or QObject with moveToThread), what is important to 
> keep in mind is:
> 
> - as said, no direct access to UI elements should ever happen *from 
> outside* the main UI thread, at least for setting properties or creating 
> objects used by the GUI in any way (eg. setting a QTextCursor);
> - the same is also valid for some UI related classes, most importantly 
> QPixmap [3]: use QImage or QPicture instead;
> - widgets cannot be moved to a thread;
> - communicating *to* a thread is possible, as long as it's done in a 
> thread-safe fashion (simple "keep running" flags, Queues, etc);
> - Qt "decides" how the signal is processed by the slots it's connected 
> to based on the thread of the receiver; if it's a QObject, and any of 
> the two (sender or receiver) reside on different threads, the signal is 
> *queued*;
> - for the above reason, objects sent from/to a thread should not be 
> expected to be "mutable" by the target thread (they never should, by the 
> way);
> - for the same reason, it's not possible to connect the started signal 
> to a function of a QObject instance that exists in the main thread: it 
> would require moving the object to the thread, which is not allowed, and 
> the result is that the signal will be queued and then the function will 
> be executed in the receiver thread;

I didn't understand this one. The started() signal of a QThread can be 
connected to a slot in any thread and the slot executed in the thread 
affine to the slot QObject.

> - while QThread should allow concurrency, the problem is that Python is 
> still "in control", meaning that a QThread will provide almost no 
> performance benefit over standard python threads: both implementations 
> obey to the GIL problem, *except* for operations directly implemented in 
> C++ or that deal with I/O operations; in practice: they don't "speed up" 
> things, they mostly ensure that the UI keeps responsive;
> 
> Finally, you could still subclass a QThread and implement a "worker 
> function" in that thread (thus allowing the default implementation to 
> execute and use the thread's event loop): just give it a different name 
> and connect it to the started signal.

On this subject I would suggest looking at QRunnable and QThreadPool as 
they provide an higher level interface for background workers that don't 
need much interaction

Let me say thank you for writing down this exhaustive analysis (which 
admittedly is far better than my 2 lines answer).

-- 
Giuseppe Corbelli


More information about the PyQt mailing list