- ベストアンサー
【VC++6.0(MFC)】スレッドの呼び出し方について
- VC++初心者のため、マルチスレッドの呼び出し方が分からない。
- 特定のクラスからスレッドを呼び出す方法について教えてほしい。
- 参考になるサイトを教えてほしい。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 動いてはいますが、10秒間停止した後に終了しています。 例えばダイアログ上のボタン1で開始、ボタン2で停止するならば、上記URLの Sleep(10000); // 10秒待つ m_isAlive = false; // スレッドを終了させる をコメントアウトして、ダイアログのメンバ変数に CHoge* m_pHoge; を追加、 ボタン1で、 m_pHoge = new CHoge(); ボタン2で delete m_pHoge; m_pHoge = NULL; といった感じでではないでしょうか。
その他の回答 (1)
- machongola
- ベストアンサー率60% (434/720)
こんばんは。補足頂きました。 ・ボタン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を設けて、現在動いているスレッドを強制終了するには? よろしくお願いします。