やること
- 並列化したい部分の変数をスレッドセーフにする
- 同時に処理を行いたくない部分の制御を追加
並列化したい部分の変数をスレッドセーフにする
普通のグローバル変数はスレッドごとに確保されないため、処理を並列化する際は、必要な変数をプライベート変数にする必要があります。
thread_local
どうしてもグローバル変数として宣言したい場合、thread_local
を使用する事でスレッドごとの静的記憶域に変数を確保することができます。
thread_local int Tmp;
int Main(){
※
AfxBeginThread(ThreadFunc0);
AfxBeginThread(ThreadFunc1);
※
}
int ThreadFunc0(){
Tmp = 2; //ThreadFunc0に対する変数「Tmp」に値を代入
・・・
}
int ThreadFunc1(){
Tmp = 4; //ThreadFunc1に対する変数「Tmp」に値を代入
・・・
}
上記のような場合は、Thread内でそれぞれ別の変数として扱うため、互いの変数に影響を与える事はありません。
Threadを立てる前にアクセスした場合や、Threadの処理が終わった後(※の部分)はどのような挙動かは、後日調査します。
同時に処理を行いたくない部分の制御を追加
同時にアクセスしたくない部分がある場合は、スレッドを同期させる必要があります。
同期をする方法は以下の4つがあります。
1. セマフォ(CSemaphore)
2. ミューテックス(CMutex)
3. イベントオブジェクト(CEvent)
4. クリティカルセクション(CCriticalSection)
今回は、セマフォを利用する。
単語の説明
セマフォとは
「共有データアクセス許可証」
スレッド間ロックに使用
実行スレッド数を制限できる
ミューテックスとは
プロセス間ロックに使用
同じプログラムを複数起動させない為の制御に使うのが有名
イベントオブジェクト
イベントが発生するのを待つ
「待ち合わせ」機能
クリティカルセクション
複数のスレッド間での相互排他の同期を行う
CSingleLock クラス
マルチスレッドプログラムで1つのリソースのアクセス制御に使うアクセスコントロール機構
実装方法
以下のように、CSemaphoreを宣言し、宣言した物を利用し、CSingleLockを宣言します。
CSingleLockのメンバ関数『Lock』『Unlock』を利用し、スレッドの制御を行います。
# include <afxmt.h> //このインクルードが必要
CSemaphore Sync; //セマフォの宣言
int ThreadMain(){
CSingleLock Lock(&Sync);
Lock.Lock();
※処理※
Lock.Unlock();
}
セマフォによって、マルチスレッドにしても『※処理※』の部分は1スレッドずつしか実行されません。
同時にアクセスされたら困る変数にアクセスする処理や、同じ変数に演算結果を格納する場合に利用しています。