MFCのマルチスレッド操作


MFCで画像自動修復ソフトを作ったのを覚えていますが、当時はマルチスレッド操作という概念はなく、画像修復アルゴリズムが複雑なので、画像修復を実行するとプログラムが詰まって他の操作ができないようです.実はMFCはこのような状況に対して1種のとても良い解決策があって、それはマルチスレッドのプログラミング技術を採用します.画像修復アルゴリズムを例にとると、それ自体に時間がかかるため、メインプログラムの操作に影響を与えることなく、スレッドを個別に開いて修復を実行することができます.
 
スレッドのいくつかの概念、およびVS 2013の例について:
MFCには2種類のスレッドがあり,それぞれ作業者スレッドとユーザインタフェーススレッドと呼ぶ.両者の主な違いは,作業者スレッドにはメッセージループがなく,ユーザインタフェーススレッドには独自のメッセージキューとメッセージループがあることである.
作業者スレッドにはメッセージメカニズムがなく、冗長な計算プロセス(画像修復アルゴリズムに適している)、プリンタのバックグラウンド印刷など、バックグラウンド計算とメンテナンスタスクを実行するために一般的に使用されます.ユーザインタフェーススレッドは、一般に、他のスレッド実行以外のユーザ入力とは独立して、ユーザおよびシステムによって生成されたイベントおよびメッセージなどに応答するために使用される.しかし、Win 32のAPIプログラミングでは、この2つのスレッドは区別されず、スレッドの起動アドレスだけでスレッドを起動してタスクを実行することができます.
この2つのスレッドの作成:

ユーザインタフェーススレッドのAfxBeginThread


ユーザインタフェーススレッドのAfxBeginThreadのプロトタイプは以下の通りである.
CWinThread* AFXAPI AfxBeginThread(   CRuntimeClass* pThreadClass,   int nPriority,   UINT nStackSize,   DWORD dwCreateFlags,   LPSECURITY_ATTRIBUTES lpSecurityAttrs)
次のようになります.
パラメータ1はCWinThreadから派生したRUNTIME_CLASSクラス;
パラメータ2は、スレッドの優先度を指定します.0の場合、スレッドを作成するスレッドと同じです.
パラメータ3は、スレッドのスタックサイズを指定し、0の場合、スレッドを作成するスレッドと同じです.
パラメータ4は、CREATE_の場合は作成IDです.SUSPENDでは、サスペンション状態でスレッドを作成し、スレッド作成後にスレッドをサスペンションします.そうしないと、スレッドは作成後にスレッドの実行を開始します.
パラメータ5はスレッドのセキュリティ属性を表し,NTの下で有用である.

ワーカースレッドのAfxBeginThread


ワーカースレッドのAfxBeginThreadのプロトタイプは以下の通りである.
CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,   LPVOID lParam,   int nPriority = THREAD_PRIORITY_NORMAL,   UINT nStackSize = 0,   DWORD dwCreateFlags = 0,   LP SECURITY_ATTRIBUTES  lpSecurityAttrs = NULL   );//ワーカースレッドの作成
戻り値:成功した場合は、新しいスレッドを指すスレッドオブジェクトのししんを返します.そうでない場合はNULLです.
pfnThreadProc:スレッドのエントリ関数、宣言は必ず以下の通りです:UINT MyThreadFunction(LPVOID pParam)、NULLに設定できません;
pParam:スレッドに伝達するパラメータは、LPVOIDのタイプであることに注意して、こうぞうたいのスレッドを伝達することができます.
nPriority:スレッドの優先度は、一般的に0に設定.プライマリスレッドと共通の優先度を持つ.
nStackSize:新しく作成するスレッドのスタックのサイズを指定します.0の場合、新しく作成されたスレッドには、プライマリ・スレッドと同じサイズのスタックがあります.
dwCreateFlags:スレッドを作成した後、スレッドにどのようなフラグがあるかを指定します.2つの値を指定できます.
CREATE_SUSPEND:スレッドが作成されると、呼び出し:ResumeThread
0:スレッドを作成すると実行を開始します.
lpSecurityAttrs:SECURITYを指す新たに作成するスレッドのセキュリティを示すATTRIBUTESの保留ステータス.NULLの場合、
新しく作成するスレッドはこうぞうたいと同様のセキュリティを有する.
プライマリスレッド内でスレッドを終了するには、スレッドをスレッド内で呼び出すことができる.
スレッドを終了する2つの方法
 
VS 2013の例:
スレッド実行関数の作成(一般的にクラス外で定義)
UINT MyThread(LPVOID pParam)

{

    int ThreatEvent = *(int* )pParam;

    if (ThreatEvent == 0)

    AfxMessageBox(_T("MyThreadProc"), MB_OK);return 1;

}

このLPVOID pParamは、任意の簡単なデータ型を伝達することができることを強調します.しかし、グローバル変数または静的変数を渡さなければなりません(これはなぜか分かりません).
 
次にスレッドを開きます.
static int k;

    k = 0;

    AfxBeginThread(MyThread, &k);

これはOnShowWindowでテストできます.
マルチスレッド間の通信:
通常、1つのセカンダリ・スレッドがプライマリ・スレッドに対して特定のタイプのタスクを完了する必要があります.これは、プライマリ・スレッドとセカンダリ・スレッドの間で通信を確立する必要があることを示すチャネルを隠します.一般的に、グローバル変数(これはLOWのように見える)の使用、イベントオブジェクトの使用、メッセージの使用など、この通信タスクを実現する方法はいくつかあります.
 
スレッド同期
マルチスレッドは私たちにメリットをもたらしますが、解決する必要がある問題も少なくありません.例えば、ディスクドライブのような独占的なシステムリソースでは、スレッドはプロセスの任意のコードセグメントを実行することができ、スレッドの実行はシステムスケジューリングによって自動的に完了し、一定の不確実性を有するため、2つのスレッドが同時にディスクドライバを操作し、操作エラーが発生する可能性がある.また、例えば、銀行システムのコンピュータでは、1つのスレッドを使用してユーザデータベースを更新し、別のスレッドを使用してデータベースを読み取り、預金者のニーズに応えることができ、データベースを読むスレッドが完全に更新されていないデータベースを読み取る可能性が高い.なぜなら、読み取り時にデータの一部だけが更新される可能性があるからである.同じプロセスに属する各スレッドを協調的に動作させることをスレッドの同期と呼ぶ.MFCは複数の同期オブジェクトを提供しています.次に、最も一般的な4つだけを紹介します.
りんかいいき
イベント(CEvent)
反発量(CMutex)
信号量(CSemaphore)
 
これらのクラスにより,スレッド同期を比較的容易に行うことができる.