Overriding QThread.run and calling the default implementation

Jeremy Katz jkatz at volexity.com
Sun Jul 4 00:36:41 BST 2021


On Fedora 32 using Python 3.8.6, the attached test works for me with
PyQt/Qt 5.15.2 and fails to service either event loop with 5.12.10.

Turning on verbose logging[1], I see that the xcb platform plugin
continues to queue events[2]. No other activity from Qt is evident.

	qt.qpa.events.reader: [heap]  0
	qt.qpa.events.reader: [heap]  1
	qt.qpa.events.reader: [heap]  2
	...

The UI thread appears to be waiting on the python global interpreter lock:
#0  0x00007ffff7a931b8 in pthread_cond_timedwait@@GLIBC_2.3.2 () from
/lib64/libpthread.so.0
#1  0x00007ffff7b9b579 in take_gil () from /lib64/libpython3.8.so.1.0
#2  0x00007ffff7bce4b5 in PyEval_RestoreThread () from
/lib64/libpython3.8.so.1.0
#3  0x00007ffff7c8e726 in PyGILState_Ensure () from
/lib64/libpython3.8.so.1.0

The worker thread has entered the event loop but appears to be idle:
#0  0x00007ffff7ed0aaf in poll () from /lib64/libc.so.6
#1  0x00007fffe75dfaae in g_main_context_iterate.constprop () from
/lib64/libglib-2.0.so.0
#2  0x00007fffe75dfbe3 in g_main_context_iteration () from
/lib64/libglib-2.0.so.0
#3  0x00007fffe9deb8ff in
QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)
() from
/mnt/hgfs/vm_shared/git/Volcano-Future/Volcano-Viewer/venv.linux-gnu.qt_5_12_10/lib64/python3.8/site-packages/PyQt5/Qt/lib/libQt5Core.so.5


The nearly identical C++ version works with both Qt 5.15.3 and 5.12.10.
This seems to be an issue within PyQt that has been resolved in newer
versions.


[1] QT_LOGGING_RULES="*.*=true"
[2]
https://code.woboq.org/qt5/qtbase/src/plugins/platforms/xcb/qxcbeventqueue.cpp.html#208


On 3/Jul/21 15:05, Maurizio Berti wrote:
> Hi Jeremy and thanks for your answer.
> The setEnabled is there just for precaution, it's not essential for the
> purpose of the test.
> 
> Shame on me, as I forgot to mention that I'm on Linux (tested and
> reproducible on an old Gentoo with PyQt5.7 as much as with a newer ~2020
> Lubuntu with PyQt5.12) and I get the whole UI frozen, including painting
> issues due to failed handling of paint events (including geometry changes).
> 
> Under some circumstances I was able to keep the UI responsive for some
> time, but at a certain point (usually after trying to resize the window)
> the UI freezes. I can also confirm that the whole main event loop is
> blocked, since I tried to add a QTimer and it doesn't time out.
> 
> Thanks,
> Maurizio
> 
> Il giorno sab 3 lug 2021 alle ore 22:13 Jeremy Katz <jkatz at volexity.com> ha
> scritto:
> 
>> On 2/Jul/21 10:55, Maurizio Berti wrote:
>>>
>>> This results in freezing the whole application as soon as the thread is
>>> started.
>>> Why does this happen? I believe it could be related to how threading
>> works
>>> and the whole wrapping, but I'm not sure and I'd like to understand the
>>> reason for this anyway.
>>
>> How are you detecting a freeze? On macOS 11 with PyQt and Qt 5.15.2, the
>> application remains responsive in my test. Removing the call to
>> self.button.setEnabled(False) and disconnecting the clicked signal
>> allows repeat clicks of the button.
>>
> 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: qthreadRunTest.py
Type: text/x-python-script
Size: 507 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20210703/a84d43c2/attachment-0001.bin>
-------------- next part --------------
#include <QApplication>
#include <QTimer>
#include <QThread>
#include <QPushButton>

class Worker : public QThread {
protected:
    void run() override { QThread::run(); }
};

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    Worker worker;

    QPushButton button("start");
    QObject::connect(&button, &QPushButton::clicked, [&worker]() { worker.start(); });
    button.show();

    QTimer uiTimer;
    QObject::connect(&uiTimer, &QTimer::timeout, []() { printf("uiTimer\n"); });
    uiTimer.start(1000);

    QTimer workerTimer;
    QObject::connect(&workerTimer, &QTimer::timeout, []() { printf("workerTimer\n"); });
    workerTimer.start(1000);
    workerTimer.moveToThread(&worker);

    return app.exec();
}

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0x095F4F2148BF111D.asc
Type: application/pgp-keys
Size: 1757 bytes
Desc: OpenPGP public key
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20210703/a84d43c2/attachment-0001.key>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 495 bytes
Desc: OpenPGP digital signature
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20210703/a84d43c2/attachment-0001.sig>


More information about the PyQt mailing list