如何停止具有无限循环的QThread

3

我有无限的线程用于数据接收:

void RxFTDI::process() {

    qDebug() << "RxFTDI hello!" << QThread::currentThreadId();

    while(true)
    {
        FT_GetStatus(ftHandle,&RxBytes,&TxBytes,&EventDWord);
//        FT_GetQueueStatus(ftHandle, &RxBytes);
        if ((ftStatus == FT_OK) && (RxBytes > 0))
        {
//            qDebug() << "rx " << RxBytes;
            FT_Read(ftHandle, &RxBuffer, RxBytes, &BytesReceived);

            if (ftStatus == FT_OK) {
                // FT_Read OK
            }
            else {
                // FT_Read Failed
            }
        }
    }
}

看起来当我想要使用 delete RxThread; 删除该线程时,我的应用程序会崩溃:

bool Ftdi::quitRxTxThreads ()
{
    emit Tx->finished();
    emit Rx->finished();

    delete Tx;
    delete Rx;

    RxThread->terminate();
    TxThread->terminate();

    delete TxThread;
    delete RxThread;

    return true;
}

完整项目在github上: https://github.com/bLLAZ/ftQt 这个想法很简单。GUI和两个独立的线程:Tx和Rx。这是我第一个C++应用程序。如果您能看一下并给些建议如何更好地组织它,我将非常感激。


3
改进之处在于消除while(true)。只需为其创建一个中断条件即可。;-) - Stefan
3
从外部终止线程始终是不建议的,应该将其视为最后一招。这可能会破坏堆栈帧、对象销毁等。我的意思是,任何事情都有可能出错。 - bartop
由于您正在使用 QThread,因此可以考虑使用其中断机制 - G.M.
3个回答

8
从外部终止线程可能会导致数据损坏,因此不应这样做。即使Qt文档也有相关警告:
“警告:该函数是危险的,不建议使用。线程可以在其代码路径的任何点被终止。在线程修改数据时可能被终止。线程没有机会在自身清理之后解锁任何持有的互斥量等。简而言之,仅在绝对必要时使用此函数。”
那么该怎么办?我想您可以使用在线程之间共享的变量来使它们优雅地完成任务,像这样将类中的一些标志放置在其中:
public:
    atomic<bool> finish = false;

然后,稍微改变一下流程:

void RxFTDI::process() {

    qDebug() << "RxFTDI hello!" << QThread::currentThreadId();

    while(!finish.load(std::memory_order_relaxed))
    {
        FT_GetStatus(ftHandle,&RxBytes,&TxBytes,&EventDWord);
//        FT_GetQueueStatus(ftHandle, &RxBytes);
        if ((ftStatus == FT_OK) && (RxBytes > 0))
        {
//            qDebug() << "rx " << RxBytes;
            FT_Read(ftHandle, &RxBuffer, RxBytes, &BytesReceived);

            if (ftStatus == FT_OK) {
                // FT_Read OK
            }
            else {
                // FT_Read Failed
            }
        }
    }
}

最后是运行线程的函数:

bool Ftdi::quitRxTxThreads ()
{
    emit Tx->finished();
    emit Rx->finished();

    delete Tx;
    delete Rx;

    RxThread->finished.store(true, std::memory_order_relaxed);
    TxThread->finished.store(true, std::memory_order_relaxed);
    //now wait for them to finish
    RxThread->wait();
    TxThread->wait();

    delete TxThread;
    delete RxThread;

    return true;
}

当然这不是最优秀的设计等诸如此类,但希望您能理解 ;)


8

从Qt 5.2开始,新增了两个函数。

bool QThread::isInterruptionRequested() const
void QThread::requestInterruption();

在您的线程中,您可以有一个永远运行的函数,并检查 isInterruptonRequested

void long_task() {
     forever {
        if ( QThread::currentThread()->isInterruptionRequested() ) {
            return;
        }
       // run your tasks
    }
}

当你想结束时,可以使用线程对象,例如从主窗口请求停止。
threadObject->requestInterruption();

需要深入研究void QThread::terminate()的使用方法,只有在极少数情况下才可以使用该函数。


2
这绝对是我迄今为止见过的最优雅的解决方案,非常感谢! - Tobbey

2

另一种方式是从另一个线程发送停止信号。使用terminated停止线程是危险的方式,我总是使用quit()然后wait()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接