解决如下问题:
- 可不断加入预执行函数
- 安全的暂停和终止线程操作
BaseThread.h
#pragma once
#include <thread>
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
using namespace std;
class BaseThread
{
public:
enum RunningState
{
START = 0,
PAUSE,
STOP
};
BaseThread();
~BaseThread() = default;
// 开启线程
void ThreadStart();
// 暂停线程
void ThreadPause();
// 终止线程
void ThreadStop();
// 得到线程状态
RunningState GetRunningState();
// 添加任务
bool AddTask(function<bool()> func);
protected:
void Run();
// 执行任务,主要是任务队列中取任务和执行任务的操作
void TaskAction();
// 挂起等待
void WaitIfPaused();
private:
RunningState m_state; // 线程状态
unique_ptr<thread> m_thread; // 包裹智能指针的线程
queue<function<bool()>> taskQueue; // 任务队列
mutex mtx; // 互斥量
condition_variable cond; // 主动暂停条件变量
condition_variable cond_queueEmpty; // 队列空条件变量
};
BaseThread.cpp
#include "BaseThread.h"
BaseThread::BaseThread() {
m_thread = unique_ptr<thread>(new thread(&BaseThread::Run, this));
m_thread->detach();
}
void BaseThread::ThreadStart(){
unique_lock<mutex> lock(mtx);
m_state = RunningState::START;
cond.notify_one();
}
void BaseThread::ThreadPause() {
unique_lock<mutex> lock(mtx);
m_state = RunningState::PAUSE;
}
void BaseThread::ThreadStop() {
unique_lock<mutex> lock(mtx);
m_state = RunningState::STOP;
cond.notify_one();
}
BaseThread::RunningState BaseThread::GetRunningState() {
return m_state;
}
void BaseThread::Run() {
m_state = RunningState::START;
cout << "thread ID:" << this_thread::get_id << " is start!\n";
// 之所以这种方法终止线程安全,是因为该执行的模块都一起执行完了才退出循环。
while (GetRunningState() != RunningState::STOP) {
WaitIfPaused();
if (GetRunningState() == RunningState::START) TaskAction();
}
cout << "Thread ID : " << this_thread::get_id << " is stop.\n";
}
void BaseThread::TaskAction() {
unique_lock<mutex> lock(mtx);
m_state = RunningState::PAUSE;
cond_queueEmpty.wait(lock, [this] {return !taskQueue.empty(); });
m_state = RunningState::START;
taskQueue.front()();
taskQueue.pop();
}
void BaseThread::WaitIfPaused() {
unique_lock<mutex> lock(mtx);
cond.wait(lock, [this] {return GetRunningState() != RunningState::PAUSE; });
}
bool BaseThread::AddTask(function<bool()> func) {
if (func == NULL) return false;
unique_lock<mutex> lock(mtx);
taskQueue.push(func);
cond_queueEmpty.notify_one();
return true;
}