优雅的退出一个正在sleep的线程

主要是依靠条件变量的直接唤醒和时间到期唤醒

QT代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Thread : public QThread
{
public:
Thread(QObject *parent = nullptr)
: QThread(parent)
{}

~Thread() { stopThread(); }

void startThread()
{
m_runing = true;
if (isRunning()) {
return;
}
start();
}

void stopThread()
{
m_runing = false;
if (isRunning()) {
m_waitCondition.wakeOne();
quit();
wait();
}
}

protected:
void run()
{
while (m_runing) {
qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << "start";
//QThread::sleep(30); 弃用
QMutexLocker locker(&m_mutex);
m_waitCondition.wait(&m_mutex, QDeadlineTimer(30 * 1000)); // 30s
qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << "stop";
}
}

private:
volatile bool m_runing = false;
QMutex m_mutex;
QWaitCondition m_waitCondition;
};

标准库代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Thread : public QThread
{
public:
Thread(QObject *parent = nullptr)
: QThread(parent)
{}

~Thread() { stopThread(); }

void startThread()
{
m_runing = true;
if (isRunning()) {
return;
}
start();
}

void stopThread()
{
m_runing = false;
if (isRunning()) {
m_cv.notify_one();
quit();
wait();
}
}

protected:
void run()
{
while (m_runing) {
qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << "start";
// std::this_thread::sleep_for(std::chrono::seconds(30)); 弃用
std::unique_lock locker(m_mutex);
m_cv.wait_for(locker, std::chrono::seconds(30)); // 30s
qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << "stop";
}
}

private:
volatile bool m_runing = false;
std::condition_variable m_cv;
std::mutex m_mutex;
};

可以在任意时间点调用 stopThread();,直接退出当前线程