2009-11-05 52 views
3

我在場景中,當線程正在根據GUI上的用戶操作運行時必須終止線程。我在Windows上使用Qt 4.5.2。一種方法如下:如何根據用戶請求安全地停止正在運行的線程?

class MyThread : public QThread 
{ 
    QMutex mutex; 
    bool stop; 

    public: 
     MyThread() : stop(false) {} 

     void requestStop() 
     { 
      QMutexLocker(&mutex); 
      stop = true; 
     } 

     void run() 
     { 
      while(counter1--) 
      { 
       QMutexLocker(&mutex); 
       if (stop) return; 

       while(counter2--) 
       { 
       } 
      } 
     } 
}; 

請注意,上面的代碼是最小的。運行功能可能需要20秒才能完成,所以我想避免鎖定和解鎖循環中的mutex變量。有沒有其他方法比這種方法更快。

在此先感謝。

回答

4

它看起來並不像你在整個內部循環中需要一個互斥體,而是像其他人說的那樣在if(stop)表達式的周圍,但是我可能會錯過你的一些應用上下文來明確地說出這一點。也許你需要requestStop()來阻塞,直到線程退出。

如果減少的互斥範圍對您來說足夠了,那麼如果將停止變量聲明爲「volatile」,則根本不需要互斥鎖。 「volatile」關鍵字導致(至少在VC++下)讀/寫內存障礙被放置在停止訪問周圍,這意味着你的requestStop()調用被保證傳遞給你的線程並且不會被緩存。以下代碼在多核處理器上應該可以很好地工作。

class MyThread : public QThread 
{ 
    volatile bool stop; 

    public: 
     MyThread() : stop(false) {} 

     void requestStop() 
     { 
      stop = true; 
     } 

     void run() 
     { 
      while(counter1--) 
      { 
       if (stop) return; 

       while(counter2--) 
       { 
       } 
      } 
     } 
}; 
+1

揮發性的相關MSDN文檔是http://msdn.microsoft.com/en-us/library/12a04hfd.aspx – Srikumar 2009-11-10 09:27:13

+0

謝謝。 volatile關鍵字的使用現在變得更加清晰。 – Donotalo 2009-11-11 03:56:38

8

它並不直接回答你的需要,但是你不能將你的互斥鎖的範圍更嚴格嗎?

while(counter1--) { 
    { 
     QMutexLocker(&mutex); 
     if (stop) return; 
    } // End locking scope : we won't read it anymore until next time 
    while(counter2--) 
... 
0

你的代碼中的主要問題是你持有的鎖比實際需要的時間長得多。在檢查stop變量後,您應該解鎖它。這應該使它快得多(取決於在內部循環中做了什麼)。無鎖選擇是使用QAtomicInt

+3

對於只能由一個線程更改的布爾值,我認爲只要將其設置爲「volatile bool stop」即可。不需要鎖定或原子整數。 – 2009-11-05 16:19:20

+0

@Jeremy,這應該作爲回答,而不是評論 – Patrick 2009-11-05 16:52:41

0

爲什麼不使用可以定期檢查的事件,並讓底層平臺擔心是否需要互斥鎖來處理事件(我假設Qt有事件對象 - 我並不是很熟悉它)。如果您使用事件對象,那麼平臺將根據需要將任何需要處理該事件的關鍵部分限定在短時間段內。另外,由於這個互斥體可能不會有太多的爭用(唯一的時候會是什麼時候想要殺死線程),抓取和釋放互斥體可能對性能影響不大。在一個需要20秒才能運行的循環中,如果影響甚至可以衡量,我會感到驚訝。但也許我錯了 - 嘗試通過計時線程來測量線程,不管是否帶有互斥量。看看你是否真的需要關注自己。

的Qt似乎並不具備我說的(一個沿的Win32的事件對象的線)的事件類型的對象,但一個QSemaphore可以很容易地被使用:首先

class MyThread : public QThread 
{ 
    QSemaphore stopFlag; 

    public: 
     MyThread() : stopFlag(1) {} 

     void requestStop() 
     { 
      stopFlag.tryAcquire(); // decrement the flag (if it hasn't been already) 
     } 

     void run() 
     { 
      while(counter1--) 
      { 
       if (!stopFlag.available()) return; 

       while(counter2--) 
       { 
       } 
      } 
     } 
}; 
0

您可以使用臨界區而不是互斥體。他們的開銷少一點。

否則你必須使用這種方法。如果您希望工作線程在某個時間間隔內終止t秒,則需要至少每t秒檢查一次終止事件。

相關問題