一个Task 状态机

Task的设计与分析

Task是一个状态机,主要用于应用在单个线程里面执行多任务的情况。VZSIP中的Task是移植google libjingle里面的Task,并对它做了一些小的适应性修改。每一个Task都是一个小型的状态机,也就是说每一个Task都有自己的状态。这些状态之间的转移是通过推动TaskRunner来进行的。TaskRunner负责运行所有的Task,让Task从一个状态转移到另一个状态,直到Task结束为止。

041335471092638.png

上图是整个状态机的类关系,一共有三个类。

  • TaskParent,是所有类的基类。这个类做的是一个连接关系,典型的中介者模式。它连接的是Task和TaskRunner两个类。
  • TaskRunner,前面已经说过,TaskRunner是推动者,里面管理了当前需要执行的Task,同时要运行所有的Task都调用TaskRunner里面的函数来运行。所有的Task要运行的话,都必须把自己注册到TaskRunner里面,然后才能够由TaskRunner统一管理并且运行。
  • Task,这是一个核心类。所有的具体任务都在这个类里面定义并且执行。每一个Task还可以有一系列的子Task,子Task还可以有子Task。这样就形成了一颗Task树。在树的最顶层就有一个Top Task。这样管理起来非常方便,我们只需要注意对这个顶层Task进行管理就行了。Task在设计的时候,同时考虑到了应用在多线程异步的情况,特别是可以与网络事件关联起来,用处非常大,后面的VZSIP里面就有关于Task与网络事件融合的情况。

所有的Task都被TaskRunner管理着,一个Task继承者可以是另一个Task的子类,也可以是TaskRunner本身。实际上,TaskRunner就是上面所说的Top Task。所有的Task都是他的Child,我们在管理的时候也只需要管理这个TaskRunner就可以控制整个业务。要启动一个Task则需要调用这个Task的Start方法,一旦调用了这个方法,就在ProcessStart()里面处理自己的业务。而我们在定义自己的Task的时候,只需要注意在什么状态下Task应该做什么样的工作这样的框架下面,专注于自己的业务,让一切变得非常简单。

下面,将会对Task进行比较深入的分析。首先每一个Task内部都有固定的几个重要的状态。

// Executes a sequence of steps
class Task : public TaskParent {
 public:
  Task(TaskParent *parent);
  virtual ~Task();
  // Omitted some content, see the code task.h
  void Start();
  void Step();
  // Omitted some content, see the code task.h 
protected:
  virtual int OnTimeout() {
    // by default, we are finished after timing out
    return STATE_DONE;
  }
 protected:
  virtual std::string GetStateName(int state) const;
  virtual int Process(int state);
  virtual void Stop();
  virtual int ProcessStart() = 0;
  virtual int ProcessResponse() { return STATE_DONE; }
  // Omitted some content, see the code task.h
};
  enum {
    STATE_BLOCKED = -1,
    STATE_INIT = 0,
    STATE_START = 1,
    STATE_DONE = 2,
    STATE_ERROR = 3,
    STATE_RESPONSE = 4,
    STATE_NEXT = 5,  // Subclasses which need more states start here and higher
  };

如上面的枚举变量所示,所有的Task都内置了这七种状态。

  • STATE_INIT,表明当前的Task刚刚初始化完成,还没有进行任务工作,当声明一个Task的时候,就会默认在这个状态下面。
  • STATE_START 当用户调用了一个Task的Start()之后,如果没有出错,就会进入这个状态。在这里面会回调用记为Task所实现的虚函数ProcessStart(),用户就可以在这里面初始化自己所想要的资源,并且做相应的任务工作。当用户在实现ProcessStart()函数的时候,他的返回值就直接状态了这个Task将进入什么样的状态中。
  • STATE_RESPONSE,这个算是Task第二个正常状态,如上面Task类里面ProcessResonse函数的实现一样,如果用户的子类中没有重载这个函数,那么进入STATE_RESPONSE状态的Task会马上进入STATE_DONE的状态。
  • STATE_DONE,当一个Task进入STATE_DONE之后,就表明这个Task已经执行完成,系统在接下来将会把这个Task删除。特别需要注意的一点是,当进入STATE_DONE之后,删除Task之前,父类是不会有什么方法通知子类要把这个Task删除的。所以,自己的重载Task的时候需要特别注意,严格执行整个Task的生命周期流程。特别是自己要清楚什么时候Task会进入STATE_DONE状态,注意在进入这个状态之前把自己相关的资源释放了。
  • STATE_NEXT,在现实过程中,一个Task可能会有很多状态,所以在这种情况下,Task也提供了接口能够自己定义自己的状态,不过需要注意的是,要扩展自己的Task就需要子类继承Task的virtual int Process(int state)函数,在这个函数里面处理自己的状态。在这里面,如果得到的是Task的基本状态,那么还是需要再调用父类的Process函数,以更能够检索到前面的状态,供整个系统管理。
  • STATE_ERROR,不管是在ProcessStartProcessResponse还是在自己所定义的状态处理函数里面,任何时候都可以返回STATE_ERROR,这个状态的处理方式和STATE_DONE类似,当出现这种错误之后,系统将会把这个Task删除了。用户在即将进入STATE_ERROR之前也需要像STATE_DONE那样,把整个Task的资源删除掉。
  • STATE_BLOCK,使用这个状态的时候要特别的小心。因为一旦进入了STATE_BLOCK之后,这个Task以后再也不会回调了。一般情况下STATE_BLOCK与Task的超时一起使用。每一个Task除了进入状态的流程管理,也可以进行超时管理。可以使用Task的set_timeout_seconds来进行超时的设置。默认情况下,一个Task是不会超时的,但是如果一量设置了超时,那么在Task超时的时候,这个Task将会被删除掉。父类在遇到超时事件的时候,会调用OnTimeout(),可以通过上面的代码看到,在父类当中,默认的OnTimeout函数仅仅是使用信息量来通知调用者,Task已经超时。调用者也能够重载这个函数,实现自己在超时的时候的一些处理。除了超时的Task会使用STATE_BLOCK状态之外,一些基于网络的Task也可以使用这个状态,这种情况下,Task除了会被自己的Task管理系统所激活,也会被网络事件所激活。而通常为了保持持续接收处理网络件事,常常在Task进入STATE_START之后,将Task设置为STATE_BLOCK状态。直到Task自身调用自己的Abort(bool nowake )或者Stop函数,通知Task管理器,将自己删除掉。

Task的状态管理,看起来是比较麻烦,主要是文字描述上面有一些缺陷。
状态转移图
如上图所示,这就是整个Task执行过程中的状态转移图。绿色都是状态,而蓝色是其中关于Task里面被执行的过程。可以看到,一般情况下只会执行里面的ProcessStart

  • 如果ProcessStart返回的是STATE_RESPONE,而自己又重载了ProcesssResponse的话,那么再会执行自己的ProcessResponse
  • 如果进入了STATE_BLOCK状态,那么只会等到自己其它地方调用AbortStop的时候才会被删除,或者自己设置了Task超时,等到OnTimeout被回调的时候再被删除。
  • 如果自己定义了STATE_NEXT状态,并且重载了Process函数,接下来的流程就由自己控制,但最终还是要回到最基本的这几个状态中来。

其它状态都不会再回调Task自身的函数了。

转载于:https://www.cnblogs.com/onebingfeng/p/4272146.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值