C++ Qt:工作线程和GUI事件之间的关系

C++ Qt:工作线程和GUI事件之间的关系,c++,qt,C++,Qt,我有一个普通的GUI线程(主窗口),并希望附加一个工作线程到它。工作线程将被实例化,移动到自己的线程,然后被激发,独立运行,运行消息传递例程(非阻塞) 这是创建工人的地方: void MainWindow::on_connectButton_clicked() { Worker* workwork; workwork= new Worker(); connect(workwork,SIGNAL(invokeTestResultsUpdate(int,quint8)),

我有一个普通的GUI线程(主窗口),并希望附加一个工作线程到它。工作线程将被实例化,移动到自己的线程,然后被激发,独立运行,运行消息传递例程(非阻塞)

这是创建工人的地方:

void MainWindow::on_connectButton_clicked()
{
    Worker* workwork;
    workwork= new Worker();

    connect(workwork,SIGNAL(invokeTestResultsUpdate(int,quint8)),
                      this,SLOT(updateTestResults(int,quint8)),Qt::QueuedConnection);
    connect(this,SIGNAL(emitInit()),workwork,SLOT(init()));

    workwork->startBC();
}
这是工人的起点:

void Worker::startBC()
{
    t1553 = new QThread();    
    this->moveToThread(t1553);
    connect(t1553,SIGNAL(started()),this,SLOT(run1553Process()));
    t1553->start();
}
关于新线程的事件队列,我这里有两个问题:

第一个也是次要的问题是,虽然我可以从工作线程接收信号(即:
invokeTestResultsUpdate
),但我不能通过从
main窗口发出
emitInit
信号来调用
init
方法。除非我直接调用它或通过
Qt::DirectConnection
连接它,否则它不会启动。为什么会这样?因为我必须显式地启动工作线程自己的消息传递循环?或者其他我不知道的事情?(尽管我尝试过,但我确实无法理解线程/事件循环/信号槽机制的概念以及它们之间的关系。我也欢迎任何新的观点。)

第二个也是更模糊的问题是:
run1553process
方法做了一些繁重的工作。我所说的繁重工作,是指数据传输率非常高。有一个循环正在运行,我尝试使用大部分
extern
API函数,在设备到达缓冲区后立即(实时)接收来自设备的数据流。然后,每当GUI接收到消息时,向GUI抛出所提到的
invokeTestResultsUpdate
信号,更新消息编号框。只不过如此

我所经历的事情很奇怪;通常,消息传递例程基本上是不受阻碍的,但当我调整主窗口的大小、移动它或隐藏/显示窗口时,工作线程会跳过许多消息。而且调整大小的动作非常慢(响应不是很快)。这真的让我得了癌症

(注意:我以前尝试过子类化QThread,但它并没有缓解问题。)

我已经阅读了所有的“线程关联性”主题,并尝试应用它们,但它的行为仍然像是在某个时刻被GUI线程的事件以某种方式打断。我可以理解MainWindow的问题,因为队列中有许多消息要执行(调用的插槽和GUI事件)。但是我不明白为什么后台线程会受到GUI事件的影响。我真的需要有一个非常强大和不受阻碍的消息例程,分别在后面运行,发射和忘记信号,不关心任何事情


我现在真的非常需要任何帮助,所以任何一点信息对我都是有用的。请毫不犹豫地提出想法。

TL;DR:call
QCoreApplication::processEvents()
内部定期运行1553进程

详细说明: 来自主线程的信号被放入队列中,并在第二个线程中的事件循环控制后执行。在您的实现中,线程一启动就调用
run1553Process
。在手动调用该函数或
QCoreApplication::processEvents
结束之前,控件将不会返回到事件循环,因此信号将在那里等待事件循环拾取它们

附言。 您正在泄漏上面代码中的辅助线程和线程

p.p.S。
来自设备的数据流通常提供一个异步API,而不必对其进行不精确的轮询

我终于找到了问题所在

关键的错误是将QThread的内置
start()
信号连接到
run1553Process()
插槽。我曾认为这是用这个方法取代
run()
,并期望一切都会好起来。但是这导致实际的
run()
方法被阻塞,因此阻止了事件循环的启动

如qthread.cpp中所述:

void QThread::run()
{
    (void) exec();
}
为了解决这个问题,我没有触摸原始的
start()
信号,而是将另一个信号独立地连接到我的
run1553Process()
。首先正常启动线程,允许事件循环启动,然后触发其他信号。这样,现在我的工作人员可以接收所有消息

我想现在我更好地理解了线程和事件之间的关系

顺便说一下,这个解决方案并没有完全解决消息跳过问题,但我觉得这是由另一个因素造成的(比如我的消息读取实现)


谢谢大家的想法。我希望这个解决方案能帮助像我这样的可怜人。

为什么有人给我的问题(-)投票?如果您对它的问题有任何评论,我将不胜感激。真的吗?您的工作线程是否正在运行事件循环?您可能需要一个线程来接收来自其他线程的排队信号。我建议您阅读以下内容以了解更多信息:我认为我的主要问题是我不知道如何在线程中运行单独的事件循环。如果您直接将
QThread
子类化,则可以在
QThread::exec()中调用
QThread::run
方法来启动事件循环。但要了解更多细节,最好阅读我在上一篇评论中提供的wiki链接。:)谢谢你,@xander。这很有帮助。@P.P.S:没错,我可以选择通过IRQ处理消息,但当我意识到我在试图使中断与其他线程配合时丢失了更多消息时,这实际上给了我更多的癌症。这种努力让我对跳过的消息产生了一种很好的恐惧。这通常只是读者的问题,而不是发送者API的限制。我想问你是如何读取信息的,但我正在从PCIe卡读取MIL-STD-1553信息。我最头疼的是“不能按制作人的价格接收”的问题。这可能是由于我缺少Qt的事件系统和线程的协调性差造成的。否则,我使用的系统在