こんばんは。補足頂きました。
・ボタン2をを使わずにスレッドの処理が終了したら、ボタン2の処理内容(スレッドの削除)を行うには?
スレッド側からダイアログクラスに向かって終了通知用のメッセージをポストします。
・ボタン1を押下のたびに新スレッドを作成するには?(CHoge* m_pHogeを配列にしてあげればよいのでしょうか。)
CArray<CHoge*>を使用した方が楽になると思います。
・新規にボタン3を設けて、現在動いているスレッドを強制終了するには?
CArray<CHoge*>の全要素を回してスレッドを止める等でしょうか。
配列の要素を操作中、スレッド間で競合する可能性もあると思うので、クリティカルセクションで排他を行わないとまずそうです。
取りあえず、ボタン1でスレッドの作成、ボタン2で稼働中の全てのスレッドの停止、1秒程でスレッドの自動停止をしていますが、色々アラもあると思うので参考程度で。
//TestDlg.cppの一番上、ヘッダのインクルードよりは下に置く(此処から)
//終了通知を受ける為のメッセージ
#define WM_ENDTHREAD (WM_USER + 100)
//スレッドクラス
class CHoge
{
public:
enum
{
READY,
RUNNING,
SUCCESS_END,
FORCE_EXIT,
};
private:
static UINT StaticProc(LPVOID pParam)
{
CHoge* pHoge = static_cast<CHoge*>(pParam);
return pHoge->ThreadProc();
}
public:
explicit CHoge(CTestDlg* pParent)
: m_pThread(NULL), m_pParent(pParent), m_iState(READY), m_iCount(0)
{
}
~CHoge()
{
}
bool RunThread()
{
if(m_pThread)
return false;
m_iState = RUNNING;
m_pThread = ::AfxBeginThread(StaticProc, this, 0, 0, CREATE_SUSPENDED);
m_pThread->m_bAutoDelete = TRUE;
m_pThread->ResumeThread();
return true;
}
void SetState(int iState)
{
m_cs.Lock();
m_iState = iState;
m_cs.Unlock();
}
int GetState() const
{
m_cs.Lock();
const int iState = m_iState;
m_cs.Unlock();
return iState;
}
HANDLE GetHandle() const
{
return m_pThread ? m_pThread->m_hThread : NULL;
}
private:
UINT ThreadProc()
{
while(1)
{
::Sleep(200);
switch(this->GetState())
{
case SUCCESS_END:
TRACE("終了\n");
m_pParent->PostMessage(WM_ENDTHREAD, 0, reinterpret_cast<LPARAM>(this));
return 0;
case FORCE_EXIT:
TRACE("強制終了\n");
return 0;
default:
TRACE("実行中\n");
this->Running();
}
}
return 0;
}
void Running()
{
//此処で処理をする
//条件を満たしたらステートを変える
if(++m_iCount > 5)
this->SetState(SUCCESS_END);
}
mutable CCriticalSection m_cs;
CWinThread* m_pThread;
CTestDlg* m_pParent;
int m_iState;
int m_iCount;
};
//(此処まで)
// TestDlg.h : ヘッダー ファイル
//
#pragma once
//追加
#include<afxmt.h>
//追加
class CHoge;
// CTestDlg ダイアログ
class CTestDlg : public CDialog
{
friend CHoge;
// コンストラクション
public:
CTestDlg(CWnd* pParent = NULL); // 標準コンストラクタ
// ダイアログ データ
enum { IDD = IDD_TEST_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV サポート
// 実装
private:
//追加
CArray<CHoge*> m_pool;
//追加
CCriticalSection m_cs;
//追加
void StartThread();
//追加
void RemoveEndThread(CHoge* pHoge);
//追加
void StopAllThread();
protected:
HICON m_hIcon;
// 生成された、メッセージ割り当て関数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
//クラスウィザードから追加
afx_msg void OnBnClickedButton1();
//クラスウィザードから追加
afx_msg void OnBnClickedButton2();
//追加
afx_msg LRESULT OnEndThread(WPARAM wParam, LPARAM lParam);
};
// TestDlg.cpp : ソース ファイル
//
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
//省略
//...
//省略
//追加
ON_MESSAGE(WM_ENDTHREAD,&CTestDlg::OnEndThread)
END_MESSAGE_MAP()
//スレッドを配列に入れてスタート
void CTestDlg::StartThread()
{
m_cs.Lock();
CHoge* pHoge = new CHoge(this);
m_pool.Add(pHoge);
pHoge->RunThread();
m_cs.Unlock();
}
//pHogeを配列から抜き取る
void CTestDlg::RemoveEndThread(CHoge* pHoge)
{
m_cs.Lock();
for(int i = 0; i < m_pool.GetCount(); ++i)
{
if(m_pool[i] != pHoge)
continue;
m_pool.RemoveAt(i);
break;
}
m_cs.Unlock();
::WaitForSingleObject(pHoge->GetHandle(), INFINITE);
delete pHoge;
}
//全てのスレッドを止める
void CTestDlg::StopAllThread()
{
CArray<HANDLE> handles;
m_cs.Lock();
for(int i = 0; i < m_pool.GetCount(); ++i)
{
handles.Add(m_pool[i]->GetHandle());
m_pool[i]->SetState(CHoge::FORCE_EXIT);
}
::WaitForMultipleObjects(handles.GetCount(), handles.GetData(), TRUE, INFINITE);
for(int i = 0; i < m_pool.GetCount(); ++i)
delete m_pool[i];
m_pool.RemoveAll();
m_cs.Unlock();
}
//ボタン1が押された
void CTestDlg::OnBnClickedButton1()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
this->StartThread();
}
//ボタン2が押された
void CTestDlg::OnBnClickedButton2()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
this->StopAllThread();
}
//スレッドが正常終了した時に来る通知
LRESULT CTestDlg::OnEndThread(WPARAM wParam, LPARAM lParam)
{
this->RemoveEndThread(reinterpret_cast<CHoge*>(lParam));
return 0;
}
補足
ご回答、ありがとうござます。 毎回のご教授、感謝しております。 できました! ありがとうございました。 今回の問題を更に発展させて、 以下の問題についてご指導頂けませんでしょうか。 ・ボタン2をを使わずにスレッドの処理が終了したら、 ボタン2の処理内容(スレッドの削除)を行うには? ・ボタン1を押下のたびに新スレッドを作成するには? (CHoge* m_pHogeを配列にしてあげればよいのでしょうか。) ・新規にボタン3を設けて、現在動いているスレッドを強制終了するには? よろしくお願いします。