マルチタスク2

InterruptTaskクラス

基本的なTaskクラスの定義としては、新しいタスクの生成を簡易化するTaskクラスを拡張する多くの方法がありますが、多くのマルチタスクのアプリケーションでは今ので十分です。便利な機能の一つは他のタスクに割り込みをかける能力です。それにより、現在の仕事が完了する前に新しい要求を扱うことが出来ます。InterruptTaskはこの形のサービスを行います。これを次のリストに示します。

InterruptTask.h
#ifndef INTERRUPTTASK
#define INTERRUPTTASK
#include "Task.h"

class InterruptTask :  public Task {
  public:
    int interruptState;
    int interruptValue;

    // コンストラクタ
    InterruptTask();

  /**
   * タスクの割り込みに用いる。割り込み状態に入る前に
   * 多重割り込みが起こった場合、最初の割り込みのみが認識されます。
   * 他の全ては無視されます。
   *
   * 入力:int interruptValue:
   *       割り込み原因を決めるためにタスクに与えられる値
   *
   * 戻り:boolean 割り込みが処理されたならばtrue
   */
  virtual bool Interrupt ( int interruptValue );

  /**
   * 割り込みの前の状態で再開する。
   * これは割り込み状態からのみ呼ばれるべきであるResume state prior to   */
  virtual void resumeInterrupt ();

  /**
   * タスクの割り込みに用いる。割り込み状態に入る前に
   * 多重割り込みが起こった場合、最初の割り込みのみが認識されます。
   * 他の全ては無視されます。
   */
  virtual bool Interrupt ();

};
#endif


InterruptTask.cpp



InterruptTask.cpp
#include "InterruptTask.h"

    // コンストラクタ
InterruptTask::InterruptTask() {
  interruptState = terminate ;
  interruptValue = 0 ;
}

bool InterruptTask::Interrupt ( int interruptValue ) {
  if ( state != Task::_interrupt ) {
    this->interruptValue = interruptValue ;
    interruptState = state ;
    state = _interrupt ;
    return true ;
  } else
  return false ;
}

void InterruptTask::resumeInterrupt () {
  state = interruptState ;
}

bool InterruptTask::Interrupt () {
  return Interrupt(0);
}

InterruptTaskは3個のメソッドと2個のオブジェクト変数を持っています。メソッドは2個のinterruptメソッドとresumeinterruptメソッドです。最初のinterruptメソッドは一つの整数型の引数を持ち、それは割り込み状態に入ったときにタスクによって参照されるinterruptValue変数に保存されます。そのタスクのexecuteメソッドはそれに従って割り込み状態を操作する必要があります。

目的は通常二つのことのうち一つをする事です。第一にinterruptValueを調べ、この情報に基づいてある操作を実行することです。二番目に次に何をするか決定することです。割り込みの前に持っていた値に状態を戻すresumeInterruptメソッドを呼ぶことによって出来ます。そのタスクが再び割り込むことが出来るように新しい状態に設定することも出来ます。

InterruptTaskは一度に一箇所からのみ割り込まれます。interruptメソッドはそのタスクがすでに割り込まれている場合はfalseを返します。

次のリストはタスククラスがTaskの代わりにInterruptTaskから拡張されていることを除いては最初のマルチタスクテストプログラムの変形です。State 1 は他のタスクが割り込まれるように変えられています。割り込むためのタスクがタスクのコンストラクターに引数として渡されています。もしその引数がnullでしたら何も起こりません。


MultitaskingTest2.h



MultitaskingTest2.h
#include "InterruptTask.h"
#define initialState 0
#define state1 1
#define state2 2
#include "common.h"

class MultitaskingTest2 : public InterruptTask {
  // execute()の状態
public:
  char* name;
  InterruptTask* taskToInterrupt ;

  MultitaskingTest2 ( char* name, InterruptTask* taskToInterrupt );
  void show ( char* text );
  void execute ();
};


MultitaskingTest2.cpp



MultitaskingTest2.cpp
#include "MultitaskingTest2.h"

MultitaskingTest2::MultitaskingTest2 ( char* name, InterruptTask* taskToInterrupt )  {
    pc.printf("MultitaskingTest2 %s\n", name);
    this->name = name ;
    this->taskToInterrupt = taskToInterrupt ;
}

void MultitaskingTest2::show ( char* text ) {
    pc.printf( "%s: %s\n", name, text ) ;
}

void MultitaskingTest2::execute ()
{
  switch ( state ) {
    case initialState:
      show ( "Initial state" ) ;
      nextState ( state1 ) ;
      break ;

    case state1:
      show ( "State 1" ) ;
      nextState ( state2 ) ;
      if ( taskToInterrupt != (Task*)null )
        if ( taskToInterrupt->Interrupt ())
          show ( "Task interrupted" ) ;
        else
          show ( "Task already interrupted" ) ;
      break ;

    case state2:
      show ( "State 2" ) ;
      stop () ;
      break ;

    case -2:
      show ( "Interrupted" ) ;
      resumeInterrupt () ;
      break ;

    default:    // 異常な状態を捕獲し停止するためにdefaultにする
      stop () ;
      break;
  } // switch
}


メインプログラム



main.cpp
#include "mbed.h"
#include "MultitaskingTest2.h"

Serial pc(USBTX, USBRX); // tx, rx

int main()
{
  pc.baud(115200);
  MultitaskingTest2* task1 = new MultitaskingTest2 ( "Task 1", (InterruptTask*)null ) ;
  new MultitaskingTest2 ( "Task 2", task1 ) ;
  new MultitaskingTest2 ( "Task 3", task1 ) ;

  Task::TaskManager () ;
  pc.printf( "All done\n" ) ;
}
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 

始めのタスクはtask1に保存され他の二つのタスクに引数を渡すことが出来ます。他の二つのタスクの各々はstate1でtask1に割り込むことを試みるでしょう。始めのタスクは割り込み状態使うだけで、InterruptValue変数はこの演習問題では用いません。始めのタスクは割り込みされたことの表示をプリントした後でその仕事を単に再開します。他の二つのタスクはtask1に割り込むことが出来るかどうかを表示するでしょう。

割り込みのサポートは制限されてはいますが役に立ちます。通常、このタイプのタスクは一つあるいはそれ以上の割り込みのタイプを扱うために設定されます。多重割り込みのタイプはinterruptメソッドのパラメータ化版を用いて扱うことが出来ます。他のタスクが何の割り込みを生じさせたかの提示はありませんが、このタイプの機能はもし必要ならば付け加えることが出来ます。一般的に、割り込みサポートを持つ理由はアプリケーションで明確にされ、その割り込みは一つの発生源か、発生源が気にならないもののどちらかでしょう。

実行結果
MultitaskingTest2 Task 1
MultitaskingTest2 Task 2
MultitaskingTest2 Task 3
Task 3: Initial state
Task 1: Initial state
Task 2: Initial state
Task 3: State 1
Task 3: Task interrupted
Task 1: Interrupted
Task 2: State 1
Task 2: Task interrupted
Task 3: State 2
Task 1: Interrupted
Task 2: State 2
Task 1: State 1
Task 1: State 2
All done