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

时间:2009-11-05 15:51:39

标签: c++ c multithreading qt

我正处于根据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变量。有没有比这种方法更快的其他方法。

提前致谢。

5 个答案:

答案 0 :(得分:8)

它不能直接满足您的需求,但是您不能将您的互斥体范围更加严格吗?

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

答案 1 :(得分: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--)
                {
                }
            }
        }
};

答案 2 :(得分:0)

您的代码中的主要问题是您持有锁的时间比您实际需要的时间长。检查stop变量后,您应该将其解锁。这应该会更快(取决于在内循环中完成的内容)。无锁定替代方法是使用QAtomicInt

答案 3 :(得分: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--)
                {
                }
            }
        }
};

答案 4 :(得分:0)

您可以使用关键部分而不是互斥锁。它们的开销要小一些。

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