Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 正确终止QThread_C++_Qt_Qthread - Fatal编程技术网

C++ 正确终止QThread

C++ 正确终止QThread,c++,qt,qthread,C++,Qt,Qthread,我有一个工人班在后台做图像采集 void acq::run () { while (m_started) { blocking_call(); } emit workFinished(); } void acq::start () { m_started = true; run(); } void acq::stop () { m_started = false; } start()stop()是插槽,workFini

我有一个工人班在后台做图像采集

void acq::run ()
{
    while (m_started)
    {
        blocking_call();
    }
    emit workFinished();
}

void acq::start ()
{
    m_started = true;
    run();
}

void acq::stop ()
{
    m_started = false;
}
start()
stop()
是插槽,
workFinished
是信号

因此,在我的UI类中,我启动worker并将信号连接到插槽:

m_thread = new QThread;
m_worker = new acq();

m_worker->moveToThread(m_thread);

// When the thread starts, then start the acquisition.
connect(m_thread, SIGNAL (started ()), m_worker, SLOT (start ()));

// When the worker has finished, then close the thread
connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));

m_thread->start();
此时,我实现了slot,
closeEvent

void UIClass::closeEvent (QCloseEvent *event)
{
    m_worker->stop(); // tell the worker to close
    m_thread->wait(); // wait until the m_thread.quit() function is called
    event->accept(); // quit the window
}
不幸的是,
m_-thread->wait()
正在阻塞。即使发出信号
quit()

谢谢

编辑:

我添加了这两个连接:

connect(m_worker, SIGNAL(workFinished()), m_worker, SLOT(deleteLater()));
connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
并将Qdebug插入
acq::~acq()


打印的消息证明调用了stop,发出了workFinished,发出了deleteLater()。

不同线程上的对象之间的正常信号/插槽连接要求接收方对象的线程运行事件循环

接收器线程理论上确实运行其事件循环,但事件循环正忙于执行
start()
插槽,因为
run()
从不返回

您需要解锁接收器事件循环,或者使用
Qt::DirectConnection
调用停止槽

在执行后一种操作时,您需要知道插槽现在在发送方线程的上下文中被调用,并且您需要防止并发访问
m_start

除了使用自己的标志,您还可以使用
QThread::requestInterruption()
QThread::isInterruptionRequested()
添加

QCoreApplication::processEvents();
到你的循环,它会工作


死锁的原因是对
acq::run()
的调用阻塞了工作线程,没有留出时间在工作线程上执行
acq::stop()

在拉尔夫·坦德茨基和凯文·克拉默的帮助下,我终于找到了解决办法

  • 而不是用
    m_worker->stop()关闭线程,我使用
    QMetaObject::invokeMethod(m_worker,“stop”,Qt::ConnectionType::QueuedConnection)
    QCoreApplication::processEvents()。这种行为不会改变,但我希望它能防止种族状况或其他问题

  • 而不是使用:
    connect(m_-worker,SIGNAL(workFinished()),m_-thread,SLOT(quit()),我使用自定义插槽:

    connect(m_worker, &Acq::workFinished, [=]
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
    });
    
    我们使用DirectConnection是因为我们在无限循环之外,所以事件不会被处理

  • 说到这里,我遇到了最后一个问题
    m_thread->wait
    被阻塞,我必须读取事件,否则,我的自定义槽将永远不会被调用。因此,在我的UI类中添加了一个事件循环
    QEventLoop m\u循环

    就在
    m_-thread->wait()之前,我编写了
    m_-loop.exec()
    最后,在我的自定义槽中,我放入
    m\u loop.quit()

    m\u loop.exec()
    处理事件,直到调用quit
    m\u loop.quit()
    。使用该方法,我甚至不需要
    m_-thread->wait()
    ,因为发出
    workFinished
    时会调用
    m_-loop.quit()
    。我不需要
    QMetaObject::invokeMethod(m_线程,“退出”,Qt::ConnectionType::DirectConnection)不再

现在它就像一个符咒


编辑:这个解决方案非常繁重和难看,Qt()建议在我的例子中使用subclass和requestinterruption。

您是否使用了调试器来确保等待的线程实际上已经终止了?如果没有终止,它在做什么?感谢您的响应。我有几个问题:-不同线程上的对象之间的正常信号/插槽连接需要接收方对象的线程运行事件循环。接受者是工人吗但是事件循环正忙于执行start()插槽,因为run()永远不会返回。如果工作进程正忙,为什么会调用stop()函数中的qDebug?你有什么例子吗?@submatuille,在你的情况下,
stop()
slot被调用了吗?@Mike是的is@Epitouille,在您将
QCoreApplication::processEvents()
添加到while循环后,是否会发生这种情况?否,它从响应的开始阶段开始发生。我不认为QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);这就是解决办法。在acq::run()循环中添加此行会阻塞我的线程。工人被困在这条线上。但是,调用acq::stop()是因为此函数(插槽)中出现了我的qDebug()。@t您是否也
QObject::invoke
acq::stop()
slot?是的,我将m_worker->stop()更改为QMetaObject::invokeMethod(m_worker,“stop”,Qt::ConnectionType::DirectConnection);它应该是一个
Qt::ConnectionType::QueuedConnection
,因此工作线程实际执行它。这避免了
m_start
上的数据竞争和这种未定义的行为。另外,我刚刚编辑了我的答案:我从
processEvents()
中删除了
QEventLoop::WaitForMoreEvents
参数。希望它现在起作用。
connect(m_worker, &Acq::workFinished, [=]
{
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
    m_loop.quit();
});