【问题标题】:Single thread application qt slot executes in which thread单线程应用qt slot在哪个线程执行
【发布时间】:2017-05-17 03:16:57
【问题描述】:

假设在一个单线程应用程序中,我创建了一个服务器并使用新的连接到达信号连接了一个插槽,如下所示,

 connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(newClientConnected()));

在这一行之后,我进入了一个巨大的循环,在那里我进行了一些计算。所以我作为主线程的单线程在循环中忙碌,现在一个新的连接到达。

所以我的问题是,

1) In which thread the new slot will be executed? I ask this because
main thread is already executing some code in a loop. 

2) In which thread the event loop is maintained? Because certainly my single
thread is executing some code in a loop and is not maintaining the event loop.

我是 QT 的新手 :(

【问题讨论】:

  • 我不太明白这个问题:你说你有一个单线程应用程序。如:只有一个线程。问一个 slot 将在哪个线程上执行很奇怪:只有一个线程,你已经知道 slot 将在哪个线程上执行!
  • @KubaOber,我想无论如何,事件循环总是被处理。这就是为什么我很好奇,如果主线程不能用于该处理,那么谁来做。
  • 你需要问一个更基本的问题:为什么你认为信号和槽必然与事件循环有关?在您的情况下,信号槽连接完全像使用函数指针。从信号体内调用插槽。当信号返回时(毕竟它只是一个方法),槽已经被调用了。没有任何地方出现任何事件循环。事件循环用于传递跨线程/排队槽调用,但你没有这样做。
  • 那么当connect函数返回时,它已经发出newConnection信号并执行了SLOT?这意味着连接调用将被阻止,直到新的连接到来?
  • 不,connect 方法只是将一个条目添加到连接列表中。它是执行所有实际调用插槽工作的信号。再次考虑一下,如果信号是函数指针,并且槽是您分配给指针的函数而不是使用connect,它将如何工作。这或多或少是这样工作的。将信号视为带有特殊调用运算符的函数指针列表:当您调用它时,列表中的任何插槽都会立即被调用(如果它们接收对象在同一个线程中,这里当然是因为没有其他线程)。

标签: multithreading qt event-loop


【解决方案1】:

主线程。

由于您运行的是单线程应用程序,所有事情都将在那里处理(除了一些基本级别的 IO)。

您的插槽将始终在调用线程中执行,除非您创建一个Qt::QueuedConnection 以在拥有该插槽的对象所属的线程中运行该插槽。一旦您运行多个线程,这一点就变得很重要。

每个标准 QThread 都有自己的事件队列。由于您有一个单线程应用程序,因此您的事件队列也将在主线程中运行。

这在您的长时间运行循环中结束,不会有任何事件处理,也不会处理新连接。

解决方案:让您长时间运行的计算在不同的线程中运行,以继续处理新的连接和事件。这里有不同的选择。

  1. 在大多数讨论中有点不受欢迎,但对于在计算期间不必处理信号/事件的长时间运行的操作仍然有效,那就是继承 QThread 并重新实现 run() 函数。

  2. 将您的计算转移到一个函数中并使用QtConcurrent::run() 运行它,它会自动使用自己的线程。

  3. 创建QRunnable的子类并使用全局线程池。

所有选项都有效,但在实现上略有不同。有关更多详细信息,请参阅文档:http://doc.qt.io/qt-5/thread-basics.html

【讨论】:

  • 非常感谢您的回答。如果我理解正确,如果一个线程只有空闲,那么它的事件循环就会起作用?在我的场景中,事件循环什么也不做,即使有新连接也不会执行插槽。
  • 由于你的循环阻塞了线程,你将没有事件处理。所以是的,你不会到达事件循环。您对连接的处理是由调用您的插槽的事件循环完成的。一旦您从插槽返回,事件处理将继续。
【解决方案2】:

事件循环在哪个线程中维护?因为当然是我的单身 线程正在循环中执行一些代码,并且没有维护事件循环。

每个线程都可以有一个事件循环。如果您的代码没有将控件返回到它运行的线程中的事件循环,那么您将不会处理任何事件,并且正在为失败做好准备。所以不要那样做。按如下方式转换您的代码:

// before
forever {
  code();
}

// after
void timerEvent(QTimerEvent *ev) {
  if (ev->timerId() == m_timer.timerId())
    code();
}

void start() {
  m_timer.start(0, this);
}

QBasicTimer m_timer; // class member

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2013-03-31
    • 2013-12-25
    • 1970-01-01
    相关资源
    最近更新 更多