【问题标题】:QTimer fires late due other thread busy with big loop由于其他线程忙于大循环,QTimer 延迟触发
【发布时间】:2017-05-02 03:06:43
【问题描述】:

环境简介: 我有一个设备运行一个用 qt 编写的应用程序。它有一个处理数据库操作(SQlite)的主线程和一个用于网络操作(通过3G)的单独线程。 主线程事件循环由 QCoreApplication::exec 运行,处理网络操作的另一个线程由 QThread::exec 运行。顺便说一句,套接字线程关联在启动后会更改(例如 moveToThread(socketThreadPtr))

问题简介: 主线程忙于一个循环,以便从数据库中选择大约 10k 条记录,该循环大约需要 +30 秒。在网络线程中有一个 15 秒的计时器,它必须在每次到期时发送一条保持活动消息。问题是 timeout() 信号的槽只有在循环结束后才会执行。

到目前为止建立的解决方案(但不令人满意): 如果我在选择记录的循环中调用 QCoreApplication::processEvents,问题就解决了,但我想知道是否存在解决方案而不是这种解决方法。

备注: 定时器、信号和槽,提供发送保持活动消息的命令当前在主线程中处理(但读/写发生在网络线程中)。另外,我在网络线程上移动了计时器,但得到的结果与在主线程上的结果相同。

【问题讨论】:

  • 由于定时器是网络相关的,它应该在网络线程上。确保连接到它的插槽也在网络线程上的对象中。
  • 计时器可能仍然存在于主线程中。第一:直接在线程上创建socket或者设置socketdescriptor并使用QueuedConnection打开socket。不要在构造函数中创建计时器并在对象上调用 movetothread,而是使用 invokeMethod 或排队的信号/插槽连接调用初始化函数。在此函数中,使用 new 创建计时器。否则计时器实际上会留在主线程中
  • 大家好!感谢您的快速回复。凯文,我把计时器完全移到了网络线程中,它在网络线程上有相应的插槽。顺便说一句,计时器是在堆上创建的。

标签: qt signals qthread qtimer qeventloop


【解决方案1】:

你必须在你的网络线程中创建定时器,也许Qtimer是网络线程的成员,所以网络线程将在主线程中构造,并且它的子线程亲和 设置为主线程,接下来你已经将网络线程移动到新的 Qthread,但是 Qtimer 呢?它仍然存在于主线程中(除非您将网络类明确定义为它的父级,因此正如您所说 moveToThread 会影响对象的子级以及 Qtimer)

Qtimer 应该在网络线程中构建,您可以在其中一个网络线程槽中构建一个新的 Qtimer 并将其连接到 Qthread::start 信号。因此,通过调用 Qthrad 的 start 方法,您的插槽将在新线程上执行,Qtimer 将分别在该线程上构造。

【讨论】:

  • 从来没有想过启动信号,如果它是那个对象的专用线程,那就太好了!
  • @SebastianLange 或许可以描述更多?
  • 贾汉达尔,你知道你是谁吗?一个很棒的人,引导我找到解决方案。非常感谢!因此,作为结论,之前我以这种方式构造了 QTimer:在构造函数中使用 new QTimer(0)。在你问我 QTimer 的亲和力之后,就是这样。所以,我以这种方式创建了 QTimer:new QTimer(this),this 是父网络线程。 QTimer 仍然在构造函数中构造。 moveToThread() 改变了对象的亲和力,它也是孩子。我缺少的儿童部分。希望我对解决方案足够清楚。如果没有,请询​​问。
  • 为了清楚起见,您现在确实有一个具有外来线程父级的类成员吗?之后你将该类对象移动到同一个线程中?如果您的线程被删除并且对象从未移动,会发生什么?或者对象被删除但线程没有被删除? QTimer,如果没有在对象析构函数中显式删除,现在仍然占用内存并在这个线程中运行。
  • QTimer 现在是网络线程的成员和子线程。这个计时器在这个线程中启动,它对应的插槽也在这个网络线程中。像魅力一样工作。
【解决方案2】:

这样的事情实际上应该在您的专用线程中创建套接字和计时器,因为您的主线程是服务器,而客户端应该在线程中处理。否则,只需在初始化函数中使用 QTcpSocket::connectToHost()QTcpServer:::bind()

主线程:

auto t = new QThread();
t->start();
auto o = new MyThreadObject();
o.moveToThread(t);
o.setDescriptor(socketDesc);
QMetaObject::invokeMethod(o, "initialize", Qt::QueuedConnection);

我的线程对象:

class MyThreadObject : public QObject
{
  Q_OBJECT
public:
  MyThreadObject(){...};
  void setDescriptor(qintptr socketdescriptor)
  {
    m_desc = socketdescriptor;
  }
public slots:
  void initialize()
  {
    m_tcpSocket = new QTcpSocket();
    m_tcpSocket->setSocketDescriptor(m_desc);
    //socket configuration
    m_timer = new QTimer();
    //timer configuration
    m_timer->start();
  }
private:
  QTcpSocket* m_tcpSocket;
  QTimer* m_timer;
  qintptr m_desc;
}

【讨论】:

    猜你喜欢
    • 2016-05-11
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多