繁体   English   中英

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

[英]How to stop a running thread safely on user request?

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

提前致谢。

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

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

首先,看起来你不需要在你的整个内循环周围需要一个互斥量,就像其他人所说的那样围绕if(停止)表达式,但我可能会错过你的一些应用程序上下文来明确地说出来。 也许你需要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--)
                {
                }
            }
        }
};

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

为什么不使用可以定期检查的事件,让底层平台担心是否需要互斥锁来处理事件(我假设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--)
                {
                }
            }
        }
};

您可以使用临界区而不是互斥锁。 它们的开销略低。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM