2009-11-05 47 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秒检查一次终止事件。

相关问题