Skip to main content.

Wednesday, August 31, 2005

MFCでの簡単なマルチスレッド処理

MFCでの比較的簡単なマルチスレッドのプログラミングについてです。一般的なマルチスレッドのプログラミングといいますと、同期処理等、複雑な制御が必要となる場合もありますが、ここでは、(ワーカ)スレッドを単独で生成して、そのスレッドでファイルの送受信、長時間の計算処理、印刷処理を行なうという場合の処理です。

私の場合はMFCでは、AfxBeginThread()を使いました。その使い方を単純なテストプログラムにしてみました。

(※ご注意 2007/09/10
申し訳ございませんが、ここの本文にはあまり出ていない部分ですが、サンプルプログラムの内部で作り方に問題がありました。詳細は、修正版の方を御覧下さい。)


実行画面



起動時



処理中



中断時

動作としては、スレッド開始ボタンでスレッド(バックグラウンドの処理)が開始され、中断ボタンで中断します。実際には何もしません。Sleep()関数で、処理をしているように見せています。

(※ご注意 2007/09/10
修正版の方では、ダイアログのクラスとスレッドをはっきりと分けて定義しています。修正版の方を参考にして下さい。)


プログラム的には、処理(スレッド)を開始、中断する画面(CDialogクラス)と、ワーカスレッド(CDialogクラスのメンバ関数)で構成されます。ワーカスレッドの定義は以下のようになります。
class CMFCThread1Dlg : public CDialog
{
    //省略
private:
    static UINT ThreadEntry(LPVOID pParam); // スレッド関数
    //省略
}
メンバ関数として定義します。staticを付けないとコンパイルエラーになります(気をつけてください)。実装部分とAfxBeginThread()でのスレッド生成は、以下のようになります。

スレッド実装部分
UINT CMFCThread1Dlg::ThreadEntry(LPVOID pParam)
{
    //生成元のダイアログクラス(同じクラス)のポインタを経由して情報を受け渡す
    CMFCThread1Dlg* pDlg = (CMFCThread1Dlg*)pParam;

    //実際の時間のかかる処理
    //省略
}
スレッド生成部分
void CMFCThread1Dlg::OnStart()
{
    //省略
    //ThreadEntry()をスレッドとして生成する
    AfxBeginThread(ThreadEntry,this); //自分自身のポインタを渡す
}
ここで要点は、呼び出し側から自分自身のthisポインタを渡して、スレッド側でそのポインタを受け取って、そのポインタ経由で画面の操作をしているという点です。同じクラスなのに変な感じもしますが?、スレッドが関数単位ということだからでしょうか?このようにします。

中断処理は、単純にフラグを画面側のメンバ変数に用意して、スレッド側の処理の区切りで、そのフラグを見ています。

VC++ 6.0のプロジェクトファイルを以下に置きました。(※2007/09/10修正版です。上記の内容とは別のプログラムです。修正版の方を参照して下さい。)
プロジェクトファイル一式

テストプログラムのレベルですので、動作は保証できません。このプログラムを利用しての不具合、不利益には一切の責任を負いかねます。ご了承ください。

参考リンク
マルチスレッドの基本的な使い方