シリアルポート(COMポート)の操作方法
その2 スレッド起動の巻




非同期モードの説明をしようかと思いましたが、その前に通信を行うにはスレッドの 説明からする必要があると思ったので、非同期はまた次回に行います。

通常の関数で通信を実現しようとすると、ReadFile()関数で受信待ちしている間は、 WriteFile()関数での送信はできないという問題が発生します。
これでは1つのプロセスで受信と送信をやらせるのは、はっきり言って無理です。
そこで登場するのがスレッドという手法です。スレッドを行うと1つのプロセスが、 同時に複数の処理を実行できるようになるのです。まあ、マルチCPUでもなければ、 厳密に同時に動くわけではありませんが。
それはさておき、スレッドを使用すると1つのプロセスで受信と送信の処理をバラバラに 行うことができるのです。

今回紹介するのはワーカスレッドといって、ユーザ操作のできないバックグラウンドでしか 動かないタイプのスレッドです。ワーカスレッドともう一つユーザスレッドがあるのですが、 こちらは私も使い方がまだ分かっていません。あしからず。

お待たせしました、それでは使い方です。

1.まずはスレッドされる関数を作成します。
(File:SimReadThread.cpp)
UINT SimReadThread(
        LPVOID pParam                      // [IN]  未使用
)
{
    BOOL        Bool_Ret;                  // 関数戻り値
    ULONG       Read_Size;                 // 読み込みバイト数
    static char ReadBuff[10];              // 読み込みバッファ
    OVERLAPPED osReader = {0};             // 非同期読み込み用構造体
    BOOL        fWaitingOnRead = FALSE;    // 非同期中メッセージ待ち状態
    BOOL        Loop_End = FALSE;          // 処理終了状態
    DWORD       dwRes;                     // 非同期読み込み完了待ち関数戻り値

    //-----------------------------------------------------------------------------
    /// 端末からの電文受信処理
    //-----------------------------------------------------------------------------

    // 電文受信待ちループ
    while( !Loop_End )
    {

      途中省略

    }
    // スレッド終了
    return(0);
}
MainFrmやViewクラスのメンバ関数にするとスレッドはうまく動作しませんでした。原因は ユーザスレッド・ワーカスレッドの違いによるものと思います。とりあえずはどこのクラス にも属さない関数を作成して下さい。
サンプルではパラメータは未使用ですが、呼び出し側でパラメータを指定する事で使用する ことも可能です。私は面倒なので、こういう動作の理解できていない関数の場合は外部変数 にしています。
スレッドの終了は何も考えずにreturn()すれば、停止してくれます。
やろうと思えば、子スレッドの終了を親スレッドで検出できると思いますが、今回のシステム ではその必要は無かったので調査していません。


2.スレッドされる関数のプロトタイプ宣言を行います。
まさか、これが分からないなどという人はおらんだろうな。


3.スレッド呼び出し処理を追加します。
(File:MainFrm.cpp)
  //-----------------------------------------------------------------------------
  /// 受信用スレッド起動処理
  //-----------------------------------------------------------------------------
  // 電文受信用スレッドを起動します
  AfxBeginThread( SimReadThread,    // スレッドの実行される関数
           NULL         // 引数
         );

  // 正常でリターンする
  return( TRUE );
}
AfxBeginThread()関数をコールすれば、後は勝手にスレッドを生成してくれます。
最初のパラメータはもちろん、関数名です。次のパラメータは引数ですが、サンプルでは 使っていません。
後は、親スレッドはAfxBeginThread()関数後の処理が動き、子スレッドはSimReadThread()関数 の中で処理が動きます。
私はMainFrm.cppからAfxBeginThread()関数をコールしているのですが、その他の場所から コールした場合は引数が違う可能性があるので注意して下さい。



N総研ソフトウェア開発部のTOPに戻る。

このページに関するご意見・質問は
ドンタコスN村 E-mail:wnaka@coco.ned.co.jp
まで送信してください。