代码之家  ›  专栏  ›  技术社区  ›  Donotalo

如何在用户请求时安全地停止正在运行的线程?

  •  3
  • Donotalo  · 技术社区  · 15 年前

    当线程根据GUI上的用户操作运行时,我必须终止线程。我在Windows上使用Qt4.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 循环中的变量。有没有比这种方法更快的方法。

    提前谢谢。

    5 回复  |  直到 15 年前
        1
  •  4
  •   Srikumar    15 年前

    首先,看起来你不需要在整个内部循环中使用互斥锁,就像其他人所说的那样,只需要在if(stop)表达式周围使用互斥锁,但我可能会遗漏一些应用程序上下文来明确地说这一点。可能需要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--)
                    {
                    }
                }
            }
    };
    
        2
  •  8
  •   Steve Schnepp    15 年前

    它不能直接满足您的需要,但是您不能更严格地定义互斥对象吗?

    while(counter1--) {
        {
          QMutexLocker(&mutex);
          if (stop) return;
        } // End locking scope : we won't read it anymore until next time
        while(counter2--)
    ...   
    
        3
  •  0
  •   LukáÅ¡ Lalinský    15 年前

    代码中的主要问题是,您持有锁的时间比实际需要的时间长得多。您应该在检查后解锁它 stop 变量这将使它更快(取决于在内部循环中执行的操作)。一种无锁的替代方法是使用 QAtomicInt

        4
  •  0
  •   billmcc    15 年前

    您可以使用临界区而不是互斥区。他们的开销少一点。

    否则,您必须使用这种方法。如果希望工作线程在某个间隔t秒内终止,则它需要至少每t秒检查一次终止事件。

        5
  •  0
  •   Michael Burr    15 年前

    为什么不使用一个可以定期检查的事件,让底层平台担心是否需要互斥来处理该事件(我假设Qt有事件对象——我对它不太熟悉)。如果您使用事件对象,平台将在必要时尽可能短的时间内确定处理该事件所需的任何关键部分的范围。

    此外,由于可能不会有太多关于互斥体的争用(唯一的时间是当有人想要杀死线程时),因此获取和释放互斥体可能对性能影响不大。在一个需要20秒才能运行的循环中,如果影响是可以测量的,我会感到惊讶。但也许我错了——试着通过计时线程来测量它,有无互斥。看看这是否是你真正需要关心的事情。

    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--)
                    {
                    }
                }
            }
    };