2013-01-06 28 views
5

我試圖殺死/取消QThread。我跟着的https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/Qt - 如何殺死QThread

執行我創建QThread的是這樣的:

workerThread = new QThread(); 
ImageProcessor* worker = new ImageProcessor(); 
worker->moveToThread(workerThread); 
connect(workerThread, SIGNAL(started()), worker, SLOT(process())); 
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit())); 
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); 
workerThread->start(); 

,並嘗試通過調用來阻止它在一定的UI事件:

workerThread->quit(); 

我的工作人員是這樣的:

class ImageProcessor : public QObject 
{ 
Q_OBJECT 
public: 
explicit ImageProcessor(QObject *parent = 0); 
~ImageProcessor(); 

signals: 
void finished(); 

public slots: 
void process(); 

private: 
//... 
}; 

其中進程調用API的計算量很大

void ImageProcessor::process() 
{ 
// API call... 

emit finished(); 
} 

我的問題是,在調用線程退出後,線程繼續運行,即API的計算不停止。由於工作人員只調用API,因此無法在工作循環中使用取消檢查。有任何想法嗎?

在此先感謝!

+0

看看這個答案 - http://stackoverflow.com/questions/14092915/qt-qthread-exclusively-for-object/14178944#14178944,它可能是你 –

回答

1

即API的計算不會停止。

那麼你試圖在計算過程中阻止它?

QThread :: quit只會停止它一切都已計算。

您可以將計算拆分爲更小的任務,甚至添加取消標誌。在ImageProcessor對象上設置一個正常方法:

class ImageProcessor{ 
    void stop(){ 
    canceled = true; 
    } 
private: 
    bool canceled; 
} 

然後檢查是否(取消)返回;在進程槽中。 (只寫bool是一種線程安全的)

然後調用stop();在對象上並在線程上退出()。

+0

的問題有用這裏,我只調用一個執行繁重計算的API函數。我不能把它分成小塊,因此不能檢查取消。 API開始它自己的生活,我不知道要阻止它... –

+1

爲什麼不讓它運行?如果你調用'workerThread-> setPriority(QThread :: IdlePriority)',它也不會使用很多資源... – BeniBela

+0

你可以運行線程直到結束,如果'取消'是真的,那麼不會發出完成的信號。 – MichK

1

您不能阻止已經阻塞的QThread,至少不能以任何安全的方式。

例如,如果你已經進入了這個功能

void neverStop() { 
    int *arr = new int[1024*1024]; 
    for (;;) { 
    } 
} 

線程將不會對任何退出消息作出反應,而大多數操作系統有一個辦法強迫線程終止,任何分配的內存不會妥善發佈。

0

而不是使用thread->quit()你應該在你的處理循環中加入一個取消標誌(適應semahpore的概念)。這意味着你可以從內部正確地阻止工人,例如,通過停止處理併發出完成的()信號。

您可以通過在工作人員中實施取消插槽(例如slot_cancelWorker())來設置標誌。然後,你可以用你的GUI將它連接:

connect(myPushButton, SIGNAL(clicked()), worker, SLOT(slot_cancelWorker())); 

當然,裏面你處理,你必須檢查掛起事件功能。因此您必須定期致電QCoreApplication::processEvents()

2

您的繁重任務非常簡單,我會使用QtConcurrent::run並忘記QThread。

ImageProcessor* worker = new ImageProcessor(); 
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
QtConcurrent::run(worker, &ImageProcessor::process); 

這正是你所需要的,它會更快一點,因爲它會使用線程池中的線程,而不是創建一個新的線程。

只記得使用Qt::AutoConnection(默認值)。

停止處理正常,你必須做一些可變的極化在你的工藝方法:

bool ImageProcessor::needEndNow() { 
    QMutexLocker locker(mutex); 
    return endNowRequested; 
} 

void ImageProcessor::requestEndNow() { 
    QMutexLocker locker(mutex); 
    endNowRequested = true; 
} 

void ImageProcessor::process() 
{ 
    while(!needEndNow()) { 
     // nextStep of processing 
    } 

    emit finished(); 
} 
1

如果你有這樣的事情,沒有任何循環:

void ImageProcessor::process() 
{ 
    worker_api(); // that takes a lot of time 
    emit finished(); 
} 

還有一點你可以用QThread做。你可以做到,從可能更好到最差:

  • 也許你正在使用的API有另一個調用來停止該工人的電話。但是既然你在這裏問,我想沒有這樣的事情。
  • 當不再需要時,使用QProcesskill啓動來自不同過程的工人呼叫。優點:不用擔心清理。對比:檢索結果可能很困難。
  • QThread::terminate,但沒有設計(見warnings in the documentation:基本上沒有清理)。
  • 在Windows中,QThread::currentThreadId爲您提供了一個您可能能夠與其他OS調用一起使用的編號(請參閱warnings in the documentation)。