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