最近研究了一下STL的thread库,做为学习成果,写了几个封装类,把thread封装起来,提供了sleep和stop方法,做为对thread的补充。
基类是AbstractThread,定义了start、stop、sleep三个公开的虚函数。start方法用于启动线程代码运行,stop方法用于终止线程代码,sleep方法供AbstractThread的子类使用,可用来暂停一段指定的时间。
AbstractThread还定义了三个保护接口虚函数:run、doStart、doIt、doStop。run函数是线程代码的外层封装,做一些初始化和收尾的工作,并调用doIt函数来执行线程代码。doStart是虚函数,被start调用,AbstractThread的子类可以重载该函数,以执行线程开始运行之前的一些准备工作。doIt函数是纯虚函数,AbstractThread的子类必须重载该函数,里面是线程的实际业务代码。doStop函数是虚函数,被stop函数调用,AbstractThread的子类可以重载该函数,以执行线程停止执行前的一些收尾工作。
AbstractThread的类定义代码(absthread.h)如下:
#ifndef __ABSTHREAD_H
#define __ABSTHREAD_H
#include <atomic>
class AbstractThread
{
public:
AbstractThread();
virtual ~AbstractThread();
public:
virtual void start();
virtual void stop(bool shouldWait = true);
virtual void sleep(unsigned long millisec);
protected:
virtual void run();
virtual void doIt() = 0;
virtual void doStart();
virtual void doStop();
protected:
std::atomic_bool waking;
std::atomic_bool running;
};
#endif /* __ABSTHREAD_H */
AbstractThread类的实现代码(absthread.cpp)如下:
#include <thread>
#include <chrono>
#include "absthread.h"
using namespace std;
using namespace chrono;
AbstractThread::AbstractThread()
{
waking = true;
running = false;
}
AbstractThread::~AbstractThread()
{
}
void AbstractThread::start()
{
waking = true;
running = true;
doStart();
thread t(this->run, this);
t.detach();
}
void AbstractThread::stop(bool shouldWait)
{
waking = true; // wake up the thread calling sleep(...).
doStop();
while(shouldWait && running);
}
void AbstractThread::sleep(unsigned long millisec)
{
system_clock::time_point start, stop;
chrono::milliseconds interval(millisec);
waking = false;
start = system_clock::now();
do {
stop = system_clock::now();
} while(((stop - start) < interval) && !waking);
}
void AbstractThread::doStart()
{
}
void AbstractThread::run()
{
running = true;
doIt();
running = false;
}
void AbstractThread::doStop()
{
}
AbstractThread类不能直接实例化,必须派生子类,子类至少要重载doIt方法,以执行线程业务代码。
在AbstractThread基础上写了一个子类PeriodicThread,这个类实现了周期性任务线程,可以设定任务的重复周期,单位为毫秒(ms)。PeriodicThread重写了doStart、doStop和run方法,并额外提供了一个纯虚函数接口doTask,用于执行需要重复执行的线程任务。
PeriodicThread的类声明代码(prdthread.h)如下所示:
#ifndef __PRDTHREAD_H
#define __PRDTHREAD_H
#include "absthread.h"
class PeriodicThread: public AbstractThread
{
public:
PeriodicThread(unsigned long period);
virtual ~PeriodicThread();
protected:
virtual void doIt();
virtual void doStart();
virtual void doStop();
virtual void doTask() = 0; // the derived class should override this method.
protected:
unsigned long period; // milli-seconds
std::atomic_bool shouldStop;
};
#endif /* __PRDTHREAD_H */
PeriodicThread类的实现代码(prdthread.cpp)如下所示:
#include <chrono>
#include "prdthread.h"
using namespace std;
using namespace chrono;
PeriodicThread::PeriodicThread(unsigned long period)
{
this->period = period;
this->shouldStop = true;
}
PeriodicThread::~PeriodicThread()
{
}
void PeriodicThread::doIt()
{
milliseconds interval(period);
system_clock::time_point startTime, stopTime;
do {
doTask();
// wait 'period' ms
startTime = system_clock::now();
do {
stopTime = system_clock::now();
} while((!shouldStop) && ((stopTime - startTime) < interval));
} while(!shouldStop);
}
void PeriodicThread::doStart()
{
shouldStop = false;
}
void PeriodicThread::doStop()
{
shouldStop = true;
}
PeriodicThread的周期定时使用了chrono库。
PeriodicThread类不能被实例化,必须派生子类,子类必须重载doTask方法,在其中执行需要重复运行的业务代码。
最后是测试代码(main.cpp),分别制作了AbstractThread的派生类LongtimeThread和PeriodicThread的派生类LoopThread。代码如下:
#include <iostream>
#include <string>
#include <memory>
#include "absthread.h"
#include "prdthread.h"
using namespace std;
class LoopThread : public PeriodicThread
{
public:
LoopThread(unsigned long period) : PeriodicThread(period)
{
count = 0;
}
virtual ~LoopThread() {}
protected:
void doTask()
{
cout << "periodic thread running " << count ++ << " loops." << endl;
}
protected:
unsigned int count;
};
class LongtimeThread : public AbstractThread
{
public:
LongtimeThread(unsigned long sleepInterval)
{
this->sleepInterval = sleepInterval;
this->shouldStop = true;
}
virtual ~LongtimeThread() {}
protected:
virtual void doIt()
{
shouldStop = false;
for(int count = 0; count < 10; count ++)
{
cout << "longtime thread running " << count << " loops." << endl;
sleep(sleepInterval);
if (shouldStop)
{
break;
}
}
}
virtual void doStop()
{
shouldStop = true;
}
protected:
unsigned long sleepInterval;
atomic_bool shouldStop;
};
int main()
{
string command;
unique_ptr<LoopThread> lt(new LoopThread(2000));
unique_ptr<LongtimeThread> ltt(new LongtimeThread(3000));
lt->start();
ltt->start();
do {
cout << ">>> input command (\"exit\" to exit): " << endl;
cin >> command;
} while(command.compare("exit") != 0);
ltt->stop(true);
lt->stop(true);
return 0;
}
程序运行后,会提示用户在键盘上输入字符串(命令),在等待用户输入的同时,两个线程也在同时执行,屏幕上会交错出现两个线程的运行时输出。如果用户在键盘上输入字符串"exit",则程序中止两个线程,并结束运行。
运行时显示的信息类似以下内容:
>>> input command ("exit" to exit):
periodic thread running 0 loops.
longtime thread running 0 loops.
periodic thread running 1 loops.
longtime thread running 1 loops.
helloperiodic thread running 2 loops.
>>> input command ("exit" to exit):
periodic thread running 3 loops.
longtime thread running 2 loops.
stop
>>> input command ("exit" to exit):
periodic thread running 4 loops.
longtime thread running 3 loops.
exit
以上代码在Eclipse CDT 9.10中调试通过。