笔记:STL的thread库应用

2 篇文章 0 订阅

最近研究了一下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中调试通过。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值