Windows版iTRONサービスコールの作成 (タスク機能)
(その4)

タスクを起動する

タスクを起動するサービスコールは以下のとおりです。


サービスコール名説明
sta_tsk

引数を指定してタスクを起動します。

act_tsk

引数を指定せずにタスクを起動します。

iact_tsk

引数を指定せずにタスクを起動します。(非タスクコンテキストからの呼出し)

can_act

タスクの起動要求をキャンセルします。

※ act_tsk()、iact_tsk() および can_act() はVer4.0のみサポートされます。

引数を指定してタスクを起動する

引数を指定してタスクを起動するには以下のサービスコールを使用します。



    ER sta_tsk( ID tskid, VP_INT stacd )
	

引数説明
tskid

タスクID番号。

stacd

タスクの起動処理に渡す引数。

戻り値説明
E_OK

正常終了。

E_ID

範囲外のタスクID番号。

E_NOEXS

指定したタスクID番号のタスクが未登録。


・サービスコールのソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  タスクの起動.
 *
 *  @param  [in]    tskid   タスクID番号.
 *  @param  [in]    stacd   タスク起動コード.
 *
 *  @retval エラーコード.
 */
ER      sta_tsk( ID tskid, VP_INT stacd )
{
    ER ercd;

    wi_CommonLock();

    //! タスクを起動する.
    ercd = wi_StartTask( tskid, (DWORD)stacd, TRUE );

    wi_CommonUnlock();
    return ercd;
}
	

タスクID番号を引数にしてタスクの起動関数を呼び出します。

引数を指定せずにタスクを起動する (ver4.0のみ)

引数を指定せずにタスクを起動するには以下のサービスコールを使用します。



    ER act_tsk( ID tskid )
	

引数説明
tskid

タスクID番号。

戻り値説明
E_OK

正常終了。

E_ID

範囲外のタスクID番号。

E_NOEXS

指定したタスクID番号のタスクが未登録。


 

割り込みハンドラや周期起動ハンドラ等の非タスク処理内からの呼び出しは、act_tsk()ではなく、iact_tsk()を使用します。


    ER iact_tsk( ID tskid )
	

引数および戻り値は act_tsk() と同じです。


※ act_tsk() および iact_tsk() の場合、タスク起動時の引数は cre_tsk() で設定したT_CTSK構造体のexinf(拡張情報)を使用します。


・サービスコールのソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  タスクの起動.
 *
 *  @param  [in]    tskid   タスクID番号.
 *
 *  @retval エラーコード.
 */
ER      act_tsk( ID tskid )
{
    ER ercd;

    wi_CommonLock();

    //! タスクを起動する.
    ercd = wi_StartTask( tskid, 0, FALSE );

    wi_CommonUnlock();
    return ercd;
}
	

タスクID番号を引数にしてタスクの起動関数を呼び出します。


・iact_tsk() サービスコールのソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  タスクの起動 (非タスクコンテキストからの呼出し用).
 *
 *  @param  [in]    tskid   タスクID番号.
 *
 *  @retval エラーコード.
 */
ER      iact_tsk( ID tskid )
{
    return act_tsk( tskid );
}
	

act_tsk()を改めて呼び出すだけですので、act_tsk()と同じ動作になります。

タスクの起動関数

タスクを起動する関数のソースコードは以下のとおりです。



/****************************************************************************/
/*!
 *  @brief  タスクの起動.
 *
 *  @param  [in]    id          タスクID番号.
 *  @param  [in]    start_code  タスク起動コード.
 *  @param  [in]    exist_stcd  TRUE = タスク起動コードあり.
 *
 *  @retval エラーコード.
 */
ER      wi_StartTask( INT id, DWORD start_code, BOOL exist_stcd )
{
    WITSKOBJ *p;

    //! タスクIDのオブジェクトを取得する.
    p = wi_GetTaskObject( id );
    if( !p ){
        return E_ID;
    }
    if( p->hThread ){
        //! スレッドが終了しているかどうかを調べる.
        DWORD code;
        if( !GetExitCodeThread( p->hThread, &code ) ){
            return E_SYS;
        }
        //! スレッドが起動中の場合.
        if( code == STILL_ACTIVE ){
            if( !exist_stcd ){
                //! act_tsk(),iact_tsk()からの呼び出しの場合は起動要求回数をカウントアップする.
                if( p->ActiveCnt + 1 > TMAX_ACTCNT ){
                    return E_QOVR;
                }
                //! 起動要求回数をカウントアップする.
                p->ActiveCnt++;
                return E_OK;
            }else{
                //! sta_tsk()からの呼び出しの場合はエラーにする.
                return E_OBJ;
            }
        }
        //! 休止中のスレッドのスレッドハンドルをクローズする.
        CloseHandle( p->hThread );
        p->hThread = NULL;
    }
    p->SuspendCnt = 0;
    p->WakeupCnt  = 0;
    p->ActiveCnt  = 0;

    if( exist_stcd ){
        //! sta_tsk()からの呼び出しの場合は引数の起動コードを使用する.
        p->StartCode = start_code;
    }else{
        //! act_tsk(),iact_tsk()からの呼び出しの場合はcre_tsk()時の拡張情報を起動コードとする.
        p->StartCode = (DWORD)p->ExtInfo;
    }

    //! タスクの状態を「実行可能状態」にする.
    p->TaskState = TTS_RDY;

    //! スレッドを休止状態で起動する.
    p->hThread = (HANDLE)_beginthreadex( NULL, 0, &UserTask, p, CREATE_SUSPENDED, &(p->ThreadId) );

    //! スレッドの優先度を設定する.
    SetThreadPriority( p->hThread, ConvertPriority( p->InitPri ) );

    //! スレッドの休止状態を解除する.
    if( ResumeThread( p->hThread ) == -1 ){
        return E_SYS;
    }
    return E_OK;
}
	

タスクを起動する関数は以下のような処理を行います。

  • 引数で指定されたタスクID番号に該当するタスク・オブジェクトを取り出します。
  • スレッド・ハンドルを既に生成している場合は以下の処理を行います。
    1. スレッドが終了しているどうかを調べます。
    2. スレッドが動作中の場合、act_tsk() または iact_tsk()からの呼び出しの場合は起動要求回数をカウントアップし処理を終了します。
    3. sta_tsk()からの呼び出しの場合はエラー終了にします。
    4. スレッドが休止中であれば、スレッド・ハンドルをクローズします。
  • タスク起動時の引数(起動コード)をタスク・オブジェクトにセットします。
  • タスクの状態を『実行可能状態』にします。
  • _beginthreadex()を呼び出して新しいスレッドを休止状態で生成します。
  • SetThreadPriority()を呼び出して新たに生成したスレッドの優先度を設定します。
  • ResumeThread()を呼び出してスレッドの休止状態を解除して処理を終了します。

スレッドを生成するのは _beginthreadex() を呼び出します。


    uintptr_t _beginthreadex( void *security,
                              unsigned stack_size,
                              unsigned ( *start_address )( void * ),
                              void *arglist,
                              unsigned initflag,
                              unsigned *thrdaddr )
	

引数説明
security

SECURITY_ATTRIBUTES構造体のポインタ。

stack_size

スタックサイズ。0の場合スタックサイズはWindowsが決めます。

start_address

スレッドの起動関数のポインタ。

arglist

スレッドに渡される引数リスト。

initflag

スレッドの起動状態。(0 = 実行中 / CREATE_SUSPENDED = 休止中)

thrdaddr

スレッド識別子を格納する領域のポインタ。

呼び出しに成功するとスレッド・ハンドルが返ります。

関数が失敗すると、NULL が返ります。


スレッドの優先度を設定するのは SetThreadPriority() を呼び出します。


    BOOL SetThreadPriority( HANDLE hThread, int nPriority )
	

引数説明
hThread

スレッドのハンドル。

nPriority

スレッドの相対優先順位値。

呼び出しに成功すると TRUE、関数が失敗すると FALSE が返ります。


スレッドの休止状態を解除するには ResumeThread() を呼び出します。


    DWORD ResumeThread( HANDLE hThread )
	

引数説明
hThread

スレッドのハンドル。

呼び出しに成功すると、関数を呼び出す前のサスペンド受付数が返ります。

関数が失敗すると、-1 が返ります。


・生成されたスレッドの起動関数のソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  ユーザータスクを起動する.
 *
 *  @param  [in]    arg     タスク・オブジェクト構造体のポインタ.
 *
 *  @retval 常に0を返す.
 */
static unsigned __stdcall UserTask( void* arg )
{
    WITSKOBJ *p = (WITSKOBJ *)arg;
    if( p ){
        //! タスクの状態を「実行中」にする.
        p->TaskState = TTS_RUN;

        //! ユーザータスクを呼び出す.
        p->TaskAdr( p->StartCode );

        //! タスクの状態を「休止中」にする.
        p->TaskState = TTS_DMT;
    }
    _endthreadex( 0 );
    return 0;
}
	

生成されたスレッドの起動関数は以下のような処理を行います。

  • タスクの状態を『実行中』にします。
  • cre_tsk() で指定されたユーザータスクのエントリ関数を呼び出します。
  • ユーザータスクが終了して処理が返ってきたらタスクの状態を『休止中』にします。
  • _endthreadex()を呼び出してスレッドを休止状態にします。

タスクの起動要求をキャンセルする (ver4.0のみ)

タスクの起動要求をキャンセルするには以下のサービスコールを使用します。



    ER can_act( ID tskid )
	

引数説明
tskid

タスクID番号。

戻り値説明
E_ID

範囲外のタスクID番号。

E_NOEXS

指定したタスクID番号のタスクが未登録。

その他の正数

キューイングされていた起動要求回数。


・サービスコールのソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  タスク起動要求のキャンセル.
 *
 *  @param  [in]    tskid   タスクID番号.
 *
 *  @retval エラーコード.
 */
ER_UINT     can_act( ID tskid )
{
    ER_UINT ercd;

    wi_CommonLock();

    //! タスクの起動要求をキャンセルする.
    ercd = (ER_UINT)wi_CancelStartReq( tskid );

    wi_CommonUnlock();
    return ercd;
}
	


・タスク起動要求のキャンセル関数のソースコードは以下のようになります。


/****************************************************************************/
/*!
 *  @brief  タスク起動要求のキャンセル.
 *
 *  @param  [in]    id      タスクID番号.
 *
 *  @retval キューイングされていた起動要求回数またはエラーコード.
 */
int     wi_CancelStartReq( INT id )
{
    int         cnt;
    ER          ercd;
    WITSKOBJ    *p;

    //! タスクIDのオブジェクトを取得する.
    p = FindTaskObject( id, &ercd );
    if( !p ){
        return ercd;
    }
    //! 起動要求回数を取り出す.
    cnt = p->ActiveCnt;

    //! 起動要求回数をクリアする.
    p->ActiveCnt = 0;

    return cnt;
}
	

タスク起動要求のキャンセル関数は以下のような処理を行います。

  • 引数で指定されたタスクID番号に該当するタスク・オブジェクトを取り出します。
  • 現在の起動要求回数を戻り値としてタスク・オブジェクトから取り出します。
  • タスク・オブジェクトの起動要求回数をクリアします。


Windowsは米国Microsoft Corporationの登録商標です。