具有Qt事件循环的可移植通用共享库设置

Portable generic shared library setup with Qt event loop

本文关键字:共享 设置 可移植 Qt 事件 循环 具有      更新时间:2023-10-16

我们试图编写一个可移植的共享库,为了方便起见,它使用了一些Qt类(主要是QTimerQTcpSocket(;虽然没有GUI的东西。根据信号/时隙连接似乎需要一些Qt事件循环,因此我们按照本答案中所述"启动"QCoreApplication。因此,我们设置了一个执行繁重工作的工作器对象,并将其移动到QThread

我们现在遇到的问题是,QThread的所有者对象(在主线程内(和QThread中的worker对象之间的排队连接似乎永远不会在Linux系统上得到处理,至少只要实现我们库的程序没有在主线程中提供任何进一步的Qt事件循环。这不是很有帮助,因为从worker传递到主线程的数据应该使用一些回调函数进一步传递,但是现在永远不会被调用。

因此,我的问题是:有没有办法让事件循环在库主线程中工作而不锁定它或主机程序(当只是在那里放置QCoreApplication::exec()或类似内容时,情况似乎就是如此(?还是我们必须建立一个不同的线程间通信方案(独立于Qt(来处理这些数据传输?

由于我们不知道主机软件是否会在QApplication上运行,理想情况下,在设置主线程事件循环之前,我也会对此进行检查。一个简单的if(qApp != nullptr)就足够了吗?

PS:我尝试过一些但对我不起作用的事情:

  • 在从主线程启动的std::thread中设置QEventLoop(可能不起作用,因为仍然不在主线程中(
  • 在主线程类中设置QEventLoop并使用QTimer定期触发其processEvents()函数(可能由于主函数中缺少QTimer::timeout信号的事件循环而不起作用(
  • std::thread中启动QCoreApplication(在Windows上给出运行时警告,指出QCoreApplication应在主线程中启动(

在Qt用语中,回调称为Qt::DirectConnection。但是,当然,这些回调将在您的工作线程上运行。但是任何其他使用回调的库都是这种情况,所以Qt在这里不是问题,你的代码也不是:基本思想具有此属性。

如果主机应用程序没有使用事件循环(任何事件循环,不一定是Qt(,那么除了轮询之外,你什么也做不了——见下文。

如果主机应用程序运行 X11 事件循环,则需要确保 Qt 副本使用与主机应用程序相同的底层事件循环。通常,这将是 glib 的事件循环,然后它应该自动工作。否则,您需要将Qt事件循环使用的同步原语的文件描述符传递给用户,并且用户需要将其集成到他们的事件循环中。无论你是否使用Qt,你都会面临同样的问题:滚动你自己的通信方法不会解决它,因为你仍然需要一个可等待的原语,它可以与用户正在使用的任何事件循环进行互操作。

当然,用户可以随时轮询回调:公开转发给QCoreApplication::processEvents()mainPoll()方法。

尽管接受了另一个答案(我认为更正确(,但我仍然想提到一个效果出奇的解决方法:我们实际上设法解决了大多数系统上的事件循环/线程问题,方法是将工作线程信号与设置worker的类的构造函数中的lambda函数连接起来。

现在,我怀疑这种行为是否正确线程安全,并且在connect函数调用中声明相对冗长的 lambda 函数肯定不是好的风格。但是,如果其他人最终遇到此问题,这可能是短期解决方案或(临时(解决方法。