代码如下:
#include <thread>
#include <memory>
namespace thread_base {
class ThreadBase {
public:
ThreadBase() : enableStop(false) {}
virtual ~ThreadBase() { enableStop = true; }
void stop() {
enableStop = true;
}
bool stopStatus() const {
return enableStop;
}
void __run__() {
run();
}
virtual void run() {
while (!enableStop) {
loop();
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
virtual void loop() = 0;
ThreadBase(const ThreadBase&) = delete;
void operator=(const ThreadBase&) = delete;
private:
bool enableStop;
};
// 启动线程
// 指针的方式
template <typename T>
inline void StartDetachThread(T* t)
{
std::thread th(&ThreadBase::__run__, t);
th.detach();
}
// 对象的方式
template <typename T>
inline void StartDetachThread(T& t)
{
StartDetachThread(&t);
}
// 智能指针的方式
template <typename T>
inline void StartDetachThread(std::shared_ptr<T>& sp)
{
StartDetachThread(sp.get());
}
};
注意:
在实现多线程类时:
1、 要禁用默认拷贝函数和赋值运算符。因为线程资源具有独占性,一个线程只能拥有对其所执行的代码和数据的访问权。如果允许线程对象的默认复制构造函数和赋值运算符,就会导致多个线程引用同一个资源,这可能会导致数据竞争或死锁等问题。
例如:
void func()
{
ThreadBase t1;
ThreadBase t2 = t1;
.
.
.
}
在这个例子中,创建了线程t1,然后将线程复制给t2,这导致两个线程引用同一个线程资源,可能导致数据竞争或死锁等问题。
因此,在实现ThreadBase类时,我们需要禁止默认拷贝,以确保每个线程对象都唯一地拥有对其所执行的代码和数据的访问权。可以通过将复制构造函数和赋值运算符声明为private或者声明为delete属性实现禁止默认拷贝。
2、函数loop我在代码中实现为纯虚函数,也可以不用哈,但是我觉得继承ThreadBase的类需要实现loop函数会更妥当一点。
3、inline void StartDetachThread(T* t)函数中要调用detach()线程分离,不用join().
将子线程与调用线程分离,彼此独立执行,调用线程不会发生阻塞,子线程执行完自动退出。
detach和join的区别:调用线程调用join后被阻塞,等到子线程运行完毕汇合后再继续后续操作,最后一起释放资源。detach不需要阻塞和汇合,调用线程和子线程完全分离,资源独立释放,可能出现调用线程结束了子线程还在后台运行的情况。