Re: running pyqt app event loop in secondary thread, using (Py)Qt6.5

Stefan Seefeld <[email protected]> Fri, 22 Sep 2023 13:53:54 -0400
Newsgroups gmane.comp.lib.qt.general,gmane.comp.python.pyqt-pykde
Message-ID <CAOEGfx3s6fr4E79=q=Tvtq1ov+QXKdFH-bdMDhFMbs5YLLBNnA@mail.gmail.com>
--===============7353355348582465267==
Content-Type: multipart/alternative; boundary="00000000000066f2060605f64b74"

--00000000000066f2060605f64b74
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi Jeremy,
thanks for the quick reply !

On Fri, Sep 22, 2023 at 1:16=E2=80=AFPM Jeremy Katz <[email protected]> wr=
ote:

>
> On 9/22/23 09:35, Stefan Seefeld wrote:
>
> > 1. run the above command, but click the "quit" button immediately. Thus
> > results in the error message `QObject::killTimer: Timers cannot be
> > stopped from another thread`,
> > followed by a segmentation fault
>
> My guess is that the QApplication object is being destroyed by the
> garbage collector, which isn't running in the QApplication's thread.
> Adding an explicit `del self.app` after the QApplication.exec returns
> prevents the crash for me.
>


Indeed, that works. (Unfortunately this approach is likely not to work in
general, as pytest appears to be holding on to references in different
places, making it highly unlikely that I can get the application's refcount
down to 0 at a specific time / location in the code.

Note that this is really just a test prototype I'm writing to understand
the underlying issues a little better. The real test logic will use a
QApplication that's exposed to Python using something other than sip
(boost.python), and I'm considering ways to deliberately circumventing the
reference counting, precisely so I can get back the control to delete the
underlying Qt objects whenever I need to, rather than when the Python
runtime would normally do it.



>
> This strategy likely won't work (AFAIK...) on macOS. While Qt is
> relatively happy to run in any thread, the mac UI interface must be used
> from the initial thread.
>
> > 2. rather than just "yielding" to the test function, yield the
> > application object (so the test function can interact with it). No
> > matter when you click the "quit" button, the result is the same as in 1=
.
> >
> > 3. call `h.app.quit()` after he `yield` (i.e. as soon as the test
> > function completes). Result: the application becomes unresponsive, but
> > doesn't stop
>
> 2 and possibly 3 sound like more instances of a wrong thread situation.
>

The call to `quit()` is documented to be thread-safe, so it should work
fine even when made programmatically from other threads than the one
running the event loop.
Is this potentially an issue with PyQt not routing the signal correctly ?

Thanks,

--=20

      ...ich hab' noch einen Koffer in Berlin...

--00000000000066f2060605f64b74
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div>Hi Jeremy,</div><div>thanks for the =
quick reply !<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr=
" class=3D"gmail_attr">On Fri, Sep 22, 2023 at 1:16=E2=80=AFPM Jeremy Katz =
&lt;<a href=3D"mailto:[email protected]">[email protected]</a>&gt; wrote:=
<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8=
ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
On 9/22/23 09:35, Stefan Seefeld wrote:<br>
<br>
&gt; 1. run the above command, but click the &quot;quit&quot; button immedi=
ately. Thus <br>
&gt; results in the error message `QObject::killTimer: Timers cannot be <br=
>
&gt; stopped from another thread`,<br>
&gt; followed by a segmentation fault<br>
<br>
My guess is that the QApplication object is being destroyed by the <br>
garbage collector, which isn&#39;t running in the QApplication&#39;s thread=
. <br>
Adding an explicit `del <a href=3D"http://self.app" rel=3D"noreferrer" targ=
et=3D"_blank">self.app</a>` after the QApplication.exec returns <br>
prevents the crash for me.<br></blockquote><div><br></div><div><br></div><d=
iv>Indeed, that works. (Unfortunately this approach is likely not to work i=
n general, as pytest appears to be holding on to references in different pl=
aces, making it highly unlikely that I can get the application&#39;s refcou=
nt down to 0 at a specific time / location in the code.</div><div><br></div=
><div>Note that this is really just a test prototype I&#39;m writing to und=
erstand the underlying issues a little better. The real test logic will use=
 a QApplication that&#39;s exposed to Python using something other than sip=
 (boost.python), and I&#39;m considering ways to deliberately circumventing=
 the reference counting, precisely so I can get back the control to delete =
the underlying Qt objects whenever I need to, rather than when the Python r=
untime would normally do it.<br></div><div><br></div><div>=C2=A0</div><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex">
<br>
This strategy likely won&#39;t work (AFAIK...) on macOS. While Qt is <br>
relatively happy to run in any thread, the mac UI interface must be used <b=
r>
from the initial thread.<br>
<br>
&gt; 2. rather than just &quot;yielding&quot; to the test function, yield t=
he <br>
&gt; application object (so the test function can interact with it). No <br=
>
&gt; matter when you click the &quot;quit&quot; button, the result is the s=
ame as in 1.<br>
&gt; <br>
&gt; 3. call `h.app.quit()` after he `yield` (i.e. as soon as the test <br>
&gt; function completes). Result: the application becomes unresponsive, but=
 <br>
&gt; doesn&#39;t stop<br>
<br>
2 and possibly 3 sound like more instances of a wrong thread situation.<br>
</blockquote></div><br clear=3D"all"><div>The call to `quit()` is documente=
d to be thread-safe, so it should work fine even when made programmatically=
 from other threads than the one running the event loop.</div><div>Is this =
potentially an issue with PyQt not routing the signal correctly ?<br></div>=
<div><br></div><div>Thanks,<br></div><div><br></div><span class=3D"gmail_si=
gnature_prefix">-- </span><br><div dir=3D"ltr" class=3D"gmail_signature"><d=
iv dir=3D"ltr"><div><img src=3D"https://ci3.googleusercontent.com/mail-sig/=
AIorK4yh4RzsqlxV6irScDGRVZ8a7NRCh_INtpPsAHx2Y8v4Vu3VKsI54RFNs3YRZk_2xTTtMMd=
SCzdNrf5XRUlmF4BkezmtZv-j5c3A4G0hEA"></div><div><pre>      ...ich hab&#39; =
noch einen Koffer in Berlin...
</pre></div></div></div></div>

--00000000000066f2060605f64b74--

--===============7353355348582465267==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Interest mailing list
[email protected]
https://lists.qt-project.org/listinfo/interest

--===============7353355348582465267==--