周期性任务执行实现模板线程类,是满足在开发过程中需要定时并周期性去执行相同任务的控制。
1.为什么要写这个线程类?
这其实跟我着手的工作主要是控制仪器的动作执行和状态返回,需要定时周期性执行相行的任务或查询仪器的各类状态。
2. 如何保证一个任务周期性并稳定的执行对仪器的多线程控制很重要,下面以的封装好的周期性任务执行线程类代码来作说明。
namespace
{
public abstract class PeriodicThread
{
private Thread threadHandle;
private int procPeriod;
private bool isActive;
private ConcurrentQueue<int> signals;
private TimingPeriod timingPeriod;
public Thread ThreadHandle
{
get { return threadHandle; }
}
public TimingPeriod TimingPeriod
{
get { return timingPeriod; }
}
public int ProcPeriod
{
get { return procPeriod; }
}
public bool IsActive
{
get { return isActive; }
}
public long ElapsedMilliseconds
{
get { return this.timingPeriod.CurrentElapsedMilliseconds; }
}
public PeriodicThread(int procPeriod)
{
this.isActive = false;
this.procPeriod = procPeriod;
this.signals = new ConcurrentQueue<int>();
this.timingPeriod = new TimingPeriod(procPeriod);
}
public void AddSignal()
{
this.signals.Enqueue(0);
}
public virtual bool Start()
{
if (!this.IsActive)
{
this.IsActive = true;
this.threadHandle = AutomateThread.StartNew(Proc, ThreadPriority.Normal);
}
return this.IsActive;
}
public virtual void Stop()
{
this.IsActive = false;
}
protected virtual bool NeedToExit()
{
return false;
}
protected virtual void RealTimeWork()
{
}
protected abstract void PeriodWork();
protected virtual void EnterWork()
{
}
protected virtual void ExitWork()
{
}
protected virtual void Proc()
{
this.timingPeriod.Reset();
AddSignal();
EnterWork();
while(this.IsActive)
{
int result;
RealTimeWork();
if (this.timingPeriod.IsNewPeriod() ||
this.signals.TryDequeue(out result))
{
//
PeriodWork();
}
if (NeedToExit())
{
break;
}
Thread.Sleep(10);
}
ExitWork();
this.IsActive = false;
}
}
}
周期性任务通过重写PeriodWork(),仔细的用户应该清楚,你所执行的任务的总的时间必须少于你执行任务的周期。从理论上,设备控制上的每个设备大部分是独占资源,很少有任务是执行的主体会比任务的周期本身轮询的时间长的。但如果你是用于其它用途,你需自己权衡如何改造以满足你自身的需求和应用。
为了实现这个周期任务类拓展性,除了满足定期执行任务的需求外,增加了5个功能:
1.支持外部需在特殊情况下需马上去执行任务: 可以调用AddSignal()来满足这一要求。
2.支持周期任务启动的准备工作:重写EnterWork()函数。
3.支持周期任务结束的退出工作:重写ExitWork函数 。
4.支持实时执行任务:重写RealTimeWork函数。
5.支持额外提前或满足指定条件退出当重执行的周期任务:重写NeedToExit()。其实这个对外接口比如在控制设备执行动作中,因发现被控制设备硬件上错误不能继续执行周期性任务时,需要退出周期任务的线程。
也许有人已经发现在这个类中还使用了另一个类TimingPeriod,此类是对时间进行计时,类似于定时器功能。下面也将此类的源码附上:
namespace
{
public class TimingPeriod
{
private const long TIME_ACCURACY = 100; //计时精度
private Tickwatch tickwatch;
private int period;
private long currentElapsedMilliseconds;
private long lastElapsedMilliseconds;
private long codeElapsedMilliseconds;
public int Period
{
get { return period; }
set { period = value; }
}
public long PeriodElapsedMilliseconds
{
get
{
return this.CurrentElapsedMilliseconds - this.LastElapsedMilliseconds;
}
}
public long CurrentElapsedMilliseconds
{
get
{
this.currentElapsedMilliseconds = this.tickwatch.ElapsedMilliseconds - this.codeElapsedMilliseconds;
this.currentElapsedMilliseconds -= this.currentElapsedMilliseconds % TIME_ACCURACY;
return this.currentElapsedMilliseconds;
}
}
public long LastElapsedMilliseconds
{
get { return lastElapsedMilliseconds; }
}
public TimingPeriod(int period)
{
this.period = period;
}
public void Reset()
{
this.tickwatch = Tickwatch.StartNew();
this.currentElapsedMilliseconds = this.tickwatch.ElapsedMilliseconds;
this.lastElapsedMilliseconds = this.tickwatch.ElapsedMilliseconds;
this.codeElapsedMilliseconds = 0;
}
public bool IsNewPeriod()
{
bool isNewPeriod = ((this.CurrentElapsedMilliseconds - this.LastElapsedMilliseconds) >= this.period);
if (isNewPeriod)
{
this.codeElapsedMilliseconds = this.tickwatch.ElapsedMilliseconds % this.period;
this.lastElapsedMilliseconds = this.tickwatch.ElapsedMilliseconds - this.codeElapsedMilliseconds;
}
return isNewPeriod;
}
}
}
这个类的为何这么实现,本身它是可以简化,如果用于对周期性执行任务的要求不高的情况。作这一处理和实现是我控制的仪器必须保证每个指定的周期指定的时刻必须去执行相应的任务。此类使用到的TickWatch是替换了C#中本身的Stopwatch类,是同事建议我Stopwatch的计时性不好(但个人在各种测试中并未发现其精度不高)。所以Tickwatch的代码我就不放上来了,如何需要留言我再补上,也可以自己仿着Stopwatch写个相同的类。
友情提示:
后续的几篇文章对其应用作了更新和封装,可以在专栏里查看。
如果感觉对你有帮助,请支持肯定下博主的努力!