「MFCの基礎 - マルチスレッド」の版間の差分
ナビゲーションに移動
検索に移動
(→作成手順) |
|||
10行目: | 10行目: | ||
== サンプルコード == | == サンプルコード == | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
// CFileView. | // CFileView.hファイル | ||
class CFileView | class CFileView | ||
{ | { | ||
17行目: | 18行目: | ||
public: | public: | ||
static UINT LoadXMLThreadFunc(void* pParam); // | static UINT LoadXMLThreadFunc(void *pParam); // 静的なワーカースレッド制御関数 | ||
void LoadXMLThreadFunc(); | void LoadXMLThreadFunc(); // ワーカースレッド本体 | ||
}; | }; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br> | <br> | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
// CFileView. | // CFileView.cppファイル | ||
void CFileView::OnButtonClick() | void CFileView::OnButtonClick() | ||
{ | { | ||
// XML読み込み処理スレッド関数を実行 | // XML読み込み処理スレッド関数を実行 | ||
m_pLoadXMLThread = ::AfxBeginThread(LoadXMLThreadFunc, this, THREAD_PRIORITY_NORMAL, | m_pLoadXMLThread = ::AfxBeginThread(LoadXMLThreadFunc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); | ||
ASSERT(m_pLoadXMLThread); | ASSERT(m_pLoadXMLThread); | ||
if(m_pLoadXMLThread) | |||
if(m_pLoadXMLThread) { | |||
m_pLoadXMLThread->m_pMainWnd = this; | m_pLoadXMLThread->m_pMainWnd = this; | ||
m_pLoadXMLThread->m_bAutoDelete = FALSE; | m_pLoadXMLThread->m_bAutoDelete = FALSE; | ||
37行目: | 39行目: | ||
// スレッド処理の開始 | // スレッド処理の開始 | ||
m_pLoadXMLThread->ResumeThread(); | m_pLoadXMLThread->ResumeThread(); | ||
while(WaitForSingleObject(m_pLoadXMLThread->m_hThread, 100) == WAIT_TIMEOUT) | while (WaitForSingleObject(m_pLoadXMLThread->m_hThread, 100) == WAIT_TIMEOUT) { | ||
// ワーカースレッドが終了するまで待機 | |||
// | |||
MSG msg; | MSG msg; | ||
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | ||
::TranslateMessage(&msg); | ::TranslateMessage(&msg); | ||
::DispatchMessage(&msg); | ::DispatchMessage(&msg); | ||
} | } | ||
} | } | ||
delete m_pLoadXMLThread; | delete m_pLoadXMLThread; | ||
} | } | ||
53行目: | 54行目: | ||
//m_pLoadXMLThread = ::AfxBeginThread(LoadXMLThreadFunc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); | //m_pLoadXMLThread = ::AfxBeginThread(LoadXMLThreadFunc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); | ||
//if(m_pLoadXMLThread) | //if(m_pLoadXMLThread) { | ||
// CRect rc; | // CRect rc; | ||
// HWND hNotifyWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_PROCESSING), this->m_hWnd, (DLGPROC)YCommonProc); | // HWND hNotifyWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_PROCESSING), this->m_hWnd, (DLGPROC)YCommonProc); | ||
61行目: | 61行目: | ||
// ::MoveWindow(hNotifyWnd, (rc.right - rc.left) / 2 - 100, (rc.bottom - rc.top) / 2 - 25, 200, 50, TRUE); | // ::MoveWindow(hNotifyWnd, (rc.right - rc.left) / 2 - 100, (rc.bottom - rc.top) / 2 - 25, 200, 50, TRUE); | ||
// m_pLoadXMLThread->m_pMainWnd = this; | // m_pLoadXMLThread->m_pMainWnd = this; | ||
// m_pLoadXMLThread->m_bAutoDelete = FALSE; | // m_pLoadXMLThread->m_bAutoDelete = FALSE; | ||
// m_pLoadXMLThread->ResumeThread(); | // m_pLoadXMLThread->ResumeThread(); | ||
// while(::WaitForSingleObject(m_pLoadXMLThread->m_hThread, 100) == WAIT_TIMEOUT) | // while(::WaitForSingleObject(m_pLoadXMLThread->m_hThread, 100) == WAIT_TIMEOUT) { | ||
// // ワーカースレッドが終了するまで待機 | |||
// // | |||
// MSG msg; | // MSG msg; | ||
// while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | // while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | ||
// ::TranslateMessage(&msg); | // ::TranslateMessage(&msg); | ||
// ::DispatchMessage(&msg); | // ::DispatchMessage(&msg); | ||
81行目: | 79行目: | ||
} | } | ||
// | // 静的なワーカースレッド制御関数 | ||
// | // 引数 : この制御関数が定義されているクラスへのポインタ | ||
// 実処理はワーカースレッド本体の関数で行う | |||
// | |||
UINT CFileView::LoadXMLThreadFunc(void *pParam) | UINT CFileView::LoadXMLThreadFunc(void *pParam) | ||
{ | { | ||
CFileView *pFileView = dynamic_cast<CFileView*>(reinterpret_cast<CWnd*>(pParam)); | CFileView *pFileView = dynamic_cast<CFileView*>(reinterpret_cast<CWnd*>(pParam)); | ||
if(pFileView) | if(pFileView) { | ||
pFileView->LoadXMLThreadFunc(); | pFileView->LoadXMLThreadFunc(); | ||
} | } | ||
return THREAD_EXIT_CODE; | return THREAD_EXIT_CODE; | ||
} | } | ||
104行目: | 96行目: | ||
void CFileView::LoadXMLThreadFunc() | void CFileView::LoadXMLThreadFunc() | ||
{ | { | ||
// | // ワーカースレッドで実行する処理 | ||
// ...略 | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
2024年12月26日 (木) 02:19時点における版
概要
MFCアプリケーションにおいて、マルチスレッドを使用する方法について記述する。
作成手順
- まず、クラスに静的なワーカースレッド関数を定義する。
- 次に、同じクラスに静的ではないワーカースレッド本体の関数を追加する。
ワーカースレッド本体の関数では、静的でないメンバ変数およびメンバ関数が使用できる。 - ワーカースレッド関数内で静的でないメンバ変数およびメンバ関数を直接使用することはできないが、
構造体等を引数として渡すことにより、クラスの関数はワーカースレッド関数にて行うことができる。
サンプルコード
// CFileView.hファイル
class CFileView
{
private:
CWinThread *m_pLoadXMLThread
public:
static UINT LoadXMLThreadFunc(void *pParam); // 静的なワーカースレッド制御関数
void LoadXMLThreadFunc(); // ワーカースレッド本体
};
// CFileView.cppファイル
void CFileView::OnButtonClick()
{
// XML読み込み処理スレッド関数を実行
m_pLoadXMLThread = ::AfxBeginThread(LoadXMLThreadFunc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
ASSERT(m_pLoadXMLThread);
if(m_pLoadXMLThread) {
m_pLoadXMLThread->m_pMainWnd = this;
m_pLoadXMLThread->m_bAutoDelete = FALSE;
// スレッド処理の開始
m_pLoadXMLThread->ResumeThread();
while (WaitForSingleObject(m_pLoadXMLThread->m_hThread, 100) == WAIT_TIMEOUT) {
// ワーカースレッドが終了するまで待機
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
delete m_pLoadXMLThread;
}
// マルチスレッドの応用(ウェイトウィンドウを表示する)
//m_pLoadXMLThread = ::AfxBeginThread(LoadXMLThreadFunc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
//if(m_pLoadXMLThread) {
// CRect rc;
// HWND hNotifyWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_PROCESSING), this->m_hWnd, (DLGPROC)YCommonProc);
// ::ShowWindow(hNotifyWnd, SW_SHOW);
// ::GetClientRect(&rc);
// ::MoveWindow(hNotifyWnd, (rc.right - rc.left) / 2 - 100, (rc.bottom - rc.top) / 2 - 25, 200, 50, TRUE);
// m_pLoadXMLThread->m_pMainWnd = this;
// m_pLoadXMLThread->m_bAutoDelete = FALSE;
// m_pLoadXMLThread->ResumeThread();
// while(::WaitForSingleObject(m_pLoadXMLThread->m_hThread, 100) == WAIT_TIMEOUT) {
// // ワーカースレッドが終了するまで待機
// MSG msg;
// while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
// ::TranslateMessage(&msg);
// ::DispatchMessage(&msg);
// }
// }
// delete m_pLoadXMLThread;
// ::DestroyWindow(hNotifyWnd);
//}
}
// 静的なワーカースレッド制御関数
// 引数 : この制御関数が定義されているクラスへのポインタ
// 実処理はワーカースレッド本体の関数で行う
UINT CFileView::LoadXMLThreadFunc(void *pParam)
{
CFileView *pFileView = dynamic_cast<CFileView*>(reinterpret_cast<CWnd*>(pParam));
if(pFileView) {
pFileView->LoadXMLThreadFunc();
}
return THREAD_EXIT_CODE;
}
// ワーカースレッド本体の関数
// スレッドの開始
void CFileView::LoadXMLThreadFunc()
{
// ワーカースレッドで実行する処理
// ...略
}
注意事項
UpdateData(TRUE)およびUpdateData(FALSE)等はマルチスレッド内で呼ぶことができない。
AfxGetMainWnd()の戻り値は、m_pLoadXMLThread->m_pMainWndに渡したウィンドウである。
設定しないとNULLが返り、また、ダイアログのCreate関数も呼ぶことができない。
そこで、スレッドの処理と同期してUIを更新する場合(UpdateData(TRUE)をスレッドから同期して呼ぶ場合)は、
下記のようにスレッド内からメインウィンドウにメッセージを送る。
// stdafx.h
//------------------------------------------------------------------------
// USER_MESSAGE
//------------------------------------------------------------------------
#define WM_USER_COMPLETE_LOAD_XML (WM_USER + 1) // XMLデータの読み込みの完了メッセージ
// CFileView.cpp
// スレッドからメイン処理にメッセージを送る & 受け取って処理
BEGIN_MESSAGE_MAP(CFileView, CDockablePane)
// UserMessage
ON_MESSAGE(WM_USER_COMPLETE_LOAD_XML, &CFileView::OnCompleteLoadXML)
END_MESSAGE_MAP()
// ワーカースレッド関数の本体にて
// XMLファイルの読み込みが完了したメッセージを送信
AfxGetMainWnd()->SendMessage(WM_USER_COMPLETE_LOAD_XML, (WPARAM)&firstIndex, (LPARAM)firstFilePath.GetString());
// CFileView.h
class CFileView
{
// 追加
afx_msg LRESULT OnCompleteLoadXML(WPARAM wParam, LPARAM lParam );
}
後は、SendMessage関数を受け取った側で処理を行えばよい。
受け取り側では、UpdateData(TRUE)およびUpdateData(FALSE)等を呼ぶことができる。
ここでスレッドを待つWaitForSingleObject関数を使用した場合、デッドロックになるので気をつけること。
スレッドの終了時に何らかの処理を行うのであれば、今回のようにスレッド終了時に"メッセージをメインウィンドウへ送る"ことで解決できる。