• 締切済み

マルチスレッドのスレッド数を増やしたい

<プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問概略> CWinThread*を使って無限ループのスレッドを作ったのですが、 無限ループのスレッドをもう一つ作り、同時に実行しようとするとアクセスバイオレーションのエラーでます。 複数スレッドの作り方を教えていただけますと幸いです。 <質問詳細> 現状の正常に実行できるソースの必要最小限を書きます。 <.h> class CMyDlg : public CDialog{ public:   static UINT ThreadFunc( LPVOID pParam );   void Thread(); // スレッドの処理 protected:   CWinThread* m_pThread;//スレッドのアドレス }; <.cpp> void CMyDlg::OnButton(){   m_pThread = AfxBeginThread( ThreadFunc, this );   for(;;) /*無限ループ処理1*/ ; } UINT CMyDlg::ThreadFunc( LPVOID pParam ){   ((CMyDlg*)pParam)->Thread();   return 0; } void CMyDlg::Thread(){   for(;;) /*無限ループ処理2*/ ; } これに、 void CMyDlg::Thread2(){   for(;;) /*無限ループ処理3*/ ; } のようなスレッドを追加したいのですが全然出来ません。 宜しければご指摘お願い致します。

みんなの回答

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.12

スレッドの実行時間は保証がありませんので厳密な時間が必要ならハード的に作ったほうがいいかと思います 別のプロセスでCPUを浪費したりした場合など実行の機会が奪われるように思います 出力ポートの端子の立ち上がり(または立下り)を検出して 10進カウンタのCLKをイネーブルにするなどの方法を検討しましょう

meeyooyoo
質問者

お礼

redfox63様、有難うございます。 厳密な時間が必要ですので、ハード的に作ることにします。 多くのご指摘頂き誠に有難うございました。 おかげ様で目的のプログラムを作成することが出来ました。

meeyooyoo
質問者

補足

度々申し訳ありませんが、再度質問が御座います。 以下ヘッダーのように宣言したFuncをスレッド関数内で呼び出すと 値がリターンされませんでした。 スレッド内でSendMessageを使って、戻り値を表示させようとすると、 「問題が発生したため試作1.exeを終了します」と 「Debug Assertion Failed! File: wincore.cpp Line: 980」 というエラーがでました。 スレッド内では他の関数を呼び出すことは出来ないのでしょうか? <.h> class CMyDlg : public CDialog { // 諸々の定義 }; double Func( double a ); //クラスの外で宣言 <.cpp> double Func( double a ) {   return a; } よろしくお願い致します。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.11

現在の OnButton1の内容はどうなっているのでしょう? この中のfor文の脱出条件を見直してみましょう

meeyooyoo
質問者

お礼

redfox63様、有難うございます。 OnButton1のfor文を見ると、break出来ていませんでした。 OnButton1( ){   MSG msg;   for( ; ; ){     while( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) AfxGetApp( )->PumpMessage( );     if( gblFlagStop == TRUE )break;   } } として、OnStop( )内でgblFlagStop = TRUEにするようにしました。 すると、全くエラーが出なくなりました。ありがとうございます! 再度質問が御座います。 マルチスレッドで実行するようになってから、一つ問題が起こるようになりました。 以下に現状のプログラムの重要な部分だけ記載しましたので、御参照願います。 ThreadFunc1とThreadFunc3を起動しなければ、ThreadFunc2は正常に動作するのですが、3つのスレッドを起動すると、ThreadFunc2でのSleep時間が指定値で動作しません。おそらく指定値より長くなっています。 (ThreadFunc1とThreadFunc3は確認していませんがSleepの指定値を厳守する必要はありません)。 これは、何が原因でしょうか? 宜しければご指摘の程お願い致します。 UINT ThreadFunc1( LPVOID lpParam )//1ms周期でデジタル入力 {   for( ; !nFLag1 ; ){     DioInput( );//デジタル入力関数     Sleep( 1 );   } } UINT ThreadFunc2( LPVOID lpParam )//10msに二回デジタル出力(スリープ時間の比率が重要) {   for( ; !nFLag2 ; ){     DioOutput( 1 );//デジタル出力関数(1を出力)     Sleep( 1 );     DioOutput( 0 );//デジタル出力関数(0を出力)     Sleep( 9 );   } } UINT ThreadFunc3( LPVOID lpParam )//1ms周期でデジタル出力 {   for( ; !nFLag3 ; ){     DioOutput( 1 );//デジタル出力関数(1を出力)     Sleep( 1 );     DioOutput( 0 );//デジタル出力関数(0を出力)     Sleep( 1 );   } }

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.10

IDEからデバッグ実行を行い、スレッドを起動、Stopボタンでスレッドを終了、CloseボタンでAppを終了 といった手順でデバッグモードが終了できるのか確認しましょう どうもAppのウィンドウが閉じてはいるが App自体が終了していないのが原因に思えます

meeyooyoo
質問者

お礼

redfox63様、有難うございます。 デバッグモードで確認したところ、CloseボタンでAppを終了してもデバッグモードが終了出来ませんでした。 App自体を終了させるにはどうしたら良いのでしょうか? ご指摘の程よろしくお願い致します。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.9

AfxBeginTheradで作成したスレッドの終了判定を WaitForSingleObjectでやっていましたが CWwinThreadは通常m_bAutoDeleteがTrueで作成されます このフラグが Trueですと制御関数の終了(またはCWinThreadの派生クラスの破棄) に伴いスレッドのハンドルも閉じられてしまって WaitForSingleObjectで判定が出来ませんでした # WaitForSingleObject関数が失敗してしまうため ・・・ スレッド作成時に m_pThread1 = AfxBeginThread( ThreadFunc1, this ); m_pThread1->m_bAutoDelete = FALSE; を実行しておいて Threadの終了確認側で m_pThread1をDeleteするようにし見てください OnStopイベントで if ( m_pThread1 ) {   // nFlag1を0以外にして Threadのループを終了させる   // InterlockedIncrement複数のスレッドから参照されても安全に   // 変更できるAPIです   ::InterlockedIncrement( &nFlag1 );   for( int n = 0; n < 100; n++ ) {     // スレッドの終了を監視     // ハンドルをm_pThread1->m_hTHreadに変更     if ( WAIT_OBJECT_0 == WaitForSngleObject( m_pTherad1->m_hThread1, 10 ) ) {       // 終了できたなら ポインタをNULLにする       // m_bAutoDeleteをFalseに設定したならば       delete m_pThread1; // を実行する必要があります       m_pThread1 = NULL;       return;     }   }   // 100回チェックしてもダメなら エラーが起きていそうです   AfxMessageBox( "Thread1が終了できません"); } else {   AfxMessageBox("Thread1はすでに終了しています"); } OnButton1の中のメッセージポンプでWM_CLOSEなどの処理をしてしまっているがfor文自体を抜けれないため 『書き込みモードで開けません』のエラーになるのではないかと考えられます

meeyooyoo
質問者

お礼

redfox63様、有難うございます。 教えて頂いた通りにしたのですが、エラー出ました。 一度コンパイルが成功しても、数分放置してからまたコンパイルすると「fatal error LNK1168: 書き込みモードで Debug/試作1.exe を開けません」がでます。 タスクマネージャのプロセスで確認すると試作1.exeが二つ実行されていて、共にCPUが50前後、メモリ使用量は7,028kバイトと7,032kバイトでした。 暫く放置した場合だけこのエラーが出ます。 この原因はなんでしょうか・・? よろしくお願いいたします。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.8

このコードでは判定できないでしょう Threadが終了しても m_pThread1は NULLにはなりません NULLにするのはプログラマの責任です ワーカースレッドとメインスレッド両方から操作するフラグが必要ですからちょっとした工夫が必要になります 本格的にやるなら CriticalSectionやMutexなどの同期オブジェクトを遣うことになります 今回のようにただループを脱出したいだけなら 単純なlong型変数を使う方法が良いでしょう メンバー変数に Threadのハンドルを保持しておきます HANDLE m_hThread1= NULL, m_hThread2 = NULL; クラスメンバーではない long型のフラグ用変数を用意します long nFlag1 = -1, nFlag2 = -1; スレッド起動前に 0で初期化します nFlag1 = 0; m_pTherad1 = afxBeginThread(...); m_hTHread1 = m_pThread1->m_hThread; スレッドのforループを for( ; !nFLag1 ; )   ; にしておきます OnStopイベントで if ( m_pThread1 ) {   // nFlag1を0以外にして Threadのループを終了させる   // InterlockedIncrement複数のスレッドから参照されても安全に   // 変更できるAPIです   ::InterlockedIncrement( &nFlag1 );   for( int n = 0; n < 100; n++ ) {     // スレッドの終了を監視     if ( WAIT_OBJECT_0 == WaitForSngleObject( m_hThread1, 10 ) ) {       // 終了できたなら ポインタをNULLにする       // m_bAutoDeleteをFalseに設定したならば       // delete m_pThread1; を実行する必要があります       m_pThread1 = NULL;       return;     }   }   // 100回チェックしてもダメなら エラーが起きていそうです   AfxMessageBox( "Thread1が終了できません"); } else {   AfxMessageBox("Thread1はすでに終了しています"); } といった具合で ・・・

meeyooyoo
質問者

お礼

redfox63様、有難う御座います。 教えていただいた通りにして、スレッド終了できました。 しかし、スレッド終了後、ダイアログの「OK」や「キャンセル」や「×」ボタンを押して、ダイアログ終了後、再度コンパイルすると、「書き込みモードで開けません」というエラーが出ます。 この状態でタスクマネージャを開くと、"プロジェクト名".exeというプログラムが実行されていて、これを強制終了すると、コンパイルエラーが無くなります。 このエラーはスレッドが終了出来ていない事が原因だと思っていたのですが、スレッド終了しても症状が治りませんでした・・。 これは何が原因なのでしょうか? この症状は、スレッド終了・ダイアログ終了後にすぐコンパイルしてもエラー出ず、数十秒後にコンパイルすると上記エラーが出ます。このエラーはマルチスレッドにしてからもう50回以上出たと思います。 ご指摘の程宜しくお願いします。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.7

メッセージマップが違いますよ > BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) これは CAboutDlgクラスのメッセージマップです これではなく BEGIN_MESSAGE_MAP(CMyDlg, CDialog) のほうのメッセージマップへ追加しましょう

meeyooyoo
質問者

補足

redfox63様、有難うございます。 メッセージマップ修正してエラー無くなり、 スレッドからメッセージを表示させることができました。 スレッドの終了と終了の確認はどのようにしたら良いでしょうか? 1.OnButton()を実行し、スレッド起動 2.OnStop()を実行し、スレッド終了 3.以降OnStop()を実行すると、「スレッドありません」と表示 という動作にしたいのですが、3.がうまくいきません。 何度OnStop()を実行しても、「スレッドありません」と表示されません。 原因はなんでしょうか? プログラムを実行し、終了させた後も、スレッドが残っているみたいで、毎回タスクマネージャで強制終了させています・・。 宜しければご指摘の程お願い致します。 以下、現在のコードです。(本当はスレッド2つ起動させてます) BOOL m_bThread1 = FALSE;//グローバル変数 void CMyDlg::OnButton(){   m_bThread1 = TRUE;   m_pThread1 = AfxBeginThread( ThreadFunc1, this );   for(;;){     while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) AfxGetApp()->PumpMessage();//メッセージポンプ     if(m_bThread1 == FALSE) break;   } } void CMyDlg::OnStop(){   if( !m_pThread1 ){     MessageBox("スレッドありません");     return;//終了   }   m_bThread1 = FALSE;//スレッドを止める } UINT ThreadFunc1(LPVOID lpParam) {   while(m_bThread == TRUE){     /*処理*/   }   return 0; }

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.6

> m_pThread = AfxBeginThread( ThreadFunc, this ); > の部分で、「2 のオーバーロードは 1 番目の引数を 'unsigned int (void *)' から要求の型に変換できません。」 ThreadFuncでは無くThreadFunc1やThreadFunc2を指示しないといけませんがその点はあってますでしょうか ThreadFunc1/ThreadFunc2はCMyDlgのメンバー関数からはずしましょう メンバー関数にするのであれば static属性にしないとダメですよ ヘッダーの class CMyDlg : public CDialog { // 諸々の定義 }; の外に宣言します UINT ThreadFunc1(LPVOID); UINT ThreadFunc2(LPVOID); といった具合です CPPファイルのほうも UINT CMyDlg::ThreadFunc1(LPVOID lpParam) { } では無く UINT ThreadFunc1(LPVOID lpParam) { } といった具合にCMyDlgクラスのメンバーから外しましょう

meeyooyoo
質問者

お礼

redfox63様、有難うございます。 教えて頂いた通りに修正してエラー無くなりました! ANo.3で教えて頂いた、ダイアログとやり取りする部分に進めてコーディングしたのですが、メッセージマップのところでエラーが出ます。 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)   ON_REGISTERED_MESSAGE(CMyDlg::m_umsgType1,OnType1) //..(1) END_MESSAGE_MAP() エラーは(1)に対して、「'OnType1' : 定義されていない識別子です。」と 「type cast' : 'int *' から 'long (__thiscall CWnd::*)(unsigned int,long)' に変換することはできません。」です。 何が原因でしょうか? 宜しければご回答お願い致します。 書いたコードを以下に書き写しましたのでご参照願います。 <.h> class CMyDlg : public CDialog { public:   static UINT m_umsgType1;   afx_msg LRESULT OnType1( WPARAM, LPARAM ); } <.cpp> UINT CMyDlg::m_umsgType1 = RegisterWindowMessage("識別用の文字列"); afx_msg LRESULT CMyDlg::OnType1( WPARAM wParam, LPARAM lParam) {   CString str( (char*)wParam );   SetDlgItemText(IDC_EDIT1,str);   return S_OK; }

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.5

お礼の部分は解決したのですね Threadからの戻り値を取得したい場合は AfxBeginThreadのdwCreateFlagsまで設定するようにしておいて m_pThread1 = AfxBeginThread( ThreadFunc1, this,THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED ); m_pThread1->m_bAutoDelete = false; m_pThread1->ResumeThread(); といった具合にします スレッドが終了したどうかは UINT dwExit1 = 0; if ( ( dwExit1 = ::GetExitCodeThread( m_pThread1->m_hThread ) ) != STILL_ACTIVE ) {   // dwExitをチェックする   delete m_pThread1;   m_pThread1 = NULL; } といった具合でしょう または m_pThread1->m_hThreadを別のメンバー変数に記憶しておいて GetExitCodeThreadに使いましょう VC++付属のMSDNで CWinThreadクラスの概要やそのページの下のほうにあるリンク先を熟読しましょう イベントハンドラ内のメッセージポンプはあまり感心しません 1msごとの更新も多すぎるような気がします 人間さんはそんなに速く更新されても理解できません 適切なタイマーイベントの実装のほうが現実的な気がしますが

meeyooyoo
質問者

お礼

redfox63様、有難う御座います。 VC++付属のMSDNでCWinThreadクラスの概要と複数のリンク先を熟読しまして、戻り値の取得の仕方はよく理解できました。 計算結果が更新された時だけ表示を更新するようにして、 さらにこれをスレッドにして、スレッドからメッセージを投げるようにしようと思います。 前回のお礼内容については、まだ解決できておりません。 m_pThread = AfxBeginThread( ThreadFunc, this ); の部分で、「2 のオーバーロードは 1 番目の引数を 'unsigned int (void *)' から要求の型に変換できません。」というエラーがでるのですが、何が原因でしょうか? 宜しくお願い致します。たびたび申し訳ありません・。

  • gentoo314
  • ベストアンサー率41% (15/36)
回答No.4

 スレッドでは、自身の処理だけを行い、画面表示はメインスレッドにやらせたほうがいいです。MFCはスレッドセーフには作られていないので、もし、スレッド内からウインドウオブジェクトに直接アクセスすると、メインスレッドとの処理がぶつかり思わぬ現象になります。  この事は、自身のクラスについてもいえます。メンバー変数を各スレッドが任意のタイミングで書き込みが行なわれることを考慮しなければなりません。  スレッド内から、他のメンバー関数を呼べないのは、スレッドの関数にstatic がついていることに着目してください。class 内で、メンバー変数、メンバー関数にstatic をつけると、インスタンスではなく、クラスの変数・関数になります。  スレッド内で発生した通知をどうすればいいかというと、 1. スレッドからメインスレッドへの受け渡し情報を検討 まとめて構造体にすればよいでしょう。 2. スレッド内でnew で受け渡し構造体バッファ確保 3. バッファ内に情報をセット 4. PostMessage の引数に、バッファアドレスを入れてコール 5. メインスレッドは、メッセージを受け取ると、構造体を参照してメッセージ表示を行う。ハンドラから抜けるときに、構造体をdelete で開放  これをもう一歩進めると、受け渡し構造体をクラス化して、スレッドをそのクラスに実装し、元のクラスからはスレッドを遮蔽することができます。UIとロジックの分離という意味もあります。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

スレッドのプロシージャは クラスのメンバーより外部の単純関数のほうがメンテナンスしやすいでしょう UINT ThreadProc1( LPVOID ); UINT ThreadProc2( LPVOID ); といった具合の宣言 UINT ThredProc1( LPVOID lpParam ) {   for( ;; )     ;   // 何らかの異常が起きた際には return 1 などを返す   return 0; } といった具合の実装にします ダイアログとやり取りするなら ダイアログのメンバーに static UINT m_umsgType1; afx_msg LRESULT OnType1( WPARAM, LPARAM ); などを宣言しておき CPPファイルに UINT CMyDlg::m_umsgType1 = RegisterWindowMessage("識別用の文字列"); を記述します BEGIN_MESSAGE_MAP(CMyDlg, CDialog)   //{{AFX_MSG_MAP(CMyDlg)   //}}AFX_MSG_MAP END_MESSAGE_MAP() といった記述があると思います   //}}AFX_MSG_MAP の次の行に   ON_REGISTERED_MESSAGE( CMyDlg::m_umsgType1, OnType1 ) を記述 afx_msg LRESULT CMyDlg::OnType1( WPARAM wParam, LPARAM lParam) {   // ここで wParamやlParamから必要な情報を得て   // ダイアログへ表示する   // たとえば wParamに文字列のアドレスがあるなら   CString str( (char*)wParam );   GetdlgItem( IDC_EDI1)->SetText( str );   // といった具合で   return S_OK; } Thread側からメッセージを投げるときは HWND hDlg = ((CMyDlg)lpParam)->m_hWnd; char buf[256]; sprintf( buf, "%d計算結果", ncalc ); SendMessage(hDlg, CMyDlg::m_umsgType1, (WPARAM)buf, NULL ); といった具合にします

meeyooyoo
質問者

お礼

redfox63様、有難うございます。 教えて頂いた、 >UINT ThreadProc1( LPVOID ); >UINT ThreadProc2( LPVOID ); >といった具合の宣言 > >UINT ThredProc1( LPVOID lpParam ) >{ >  for( ;; ) >    ; >  // 何らかの異常が起きた際には return 1 などを返す >  return 0; >} の部分をやってみたのですが、質問文にあるOnButton()内の、 m_pThread = AfxBeginThread( ThreadFunc, this ); の部分で、「2 のオーバーロードは 1 番目の引数を 'unsigned int (void *)' から要求の型に変換できません。」というエラーがでるようになりました。 宣言で「static」を消しただけでは、ダメなのでしょうか? 宜しければご指摘の程お願い致します。

meeyooyoo
質問者

補足

質問を補足させて頂きます。 void CMyDlg::OnButton(){   m_pThread1 = AfxBeginThread( ThreadFunc1, this );   m_pThread2 = AfxBeginThread( ThreadFunc2, this );   for(;;){     //メッセージポンプをここに挿入     MSG msg;     while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) AfxGetApp()->PumpMessage();     if(/*グローバル変数BOOL blEnd == TRUE) break;     m_Display =csMessage;     UpdateData(FALSE);UpdateWindow();     Sleep(1);   } } 上記のように、OnButton()はスレッド二つを起動したら無限ループに入り、1ms毎にダイアログエディットボックスメンバ変数m_Displayに文字列csMessageを代入し、表示させています。この使いかたも良くないでしょうか? また、ThreadFunc1()とThreadFunc2()の戻り値を受け取る方法が分かりません。(スレッドがどこに値を返しているのか分かりません・・。) よろしくお願いします。

関連するQ&A

  • c++でスレッド処理

    vc++6.0でスレッドを使ったアプリケーションを作っています。 AfxBeginThreadを使って UINT Action::reactiveMotionTh( LPVOID pvParam) {   Action *rm = (Action *)pvParam; ・   ・   ・ return 0; } CWinThread* ch = AfxBeginThread(reactiveMotionTh, (LPVOID)this); と書いたのですが、実行しようとすると、 error C2065: 'AfxBeginThread' : 定義されていない識別子です。 とエラーがでます。何が問題なんでしょうか。よろしくお願いします。

  • [VC++] AfxBeginThreadで生成したスレッドの監視方法について

    お世話になります。 VC++でスレッドプログラムを作っています。 AfxBeginThreadでワーカースレッドを作成し、その中でダイアログを表示する プログラムです。 問題は、ワーカースレッドがある処理状態に至ったことを メインスレッドで検知したいのですが、それがうまく いかないということです。 コードの概略をしめします。 <メインスレッド側> void CTestApp::OnTest() {   CTestDlg dlg;   dlg.IsContinue = FALSE;   pThread = AfxBeginThread(TestDlg::Thread, (void*)&dlg);   while (!dlg.IsContinue) { // <----問題:このループ処理を抜けれない!    Sleep(0);   } } <ワーカースレッド側> UINT TestDlg::Thread(LPVOID pParam){   TestDlg* pDlg = (TestDlg*)pParam;   pDlg->Create(TestDlg::IDD);   pDlg->ShowWindow(SW_SHOW);     pDlg->IsContinue = TRUE; //<--ここでフラグを変更しているのに。   while(pDlg->IsContinue) {    MSG msg;    if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {      ::TranslateMessage(&msg);      ::DispatchMessage(&msg);    }   }   pDlg->DestroyWindow();   return 0; } ---- メインスレッドのSleep(0)で待つのを AfxGetApp()->PumpMessage()に変更すると ループを抜けるようなのですが、どうも納得できません。 上記のプログラムで問題、もしくはプロジェクトの 設定等に不備がある可能性がありましたら 御教授いただけたら幸いです。 よろしくおねがいいたします。

  • [MFC]AfxBeginTreadでのスレッド強制終了の方法について

    WinInetで多数のクライアントとHTTP通信を行うプログラムを作成しています。 やりたい事は閉じたネットワークの中で 生きているホストを調べるということです。 HTTP_GETの可否で判断させるつもりですがpingでも構いません。 (DHCPサーバーのリース情報などは参照できない状態環境) 逐次処理で一台ずつタイムアウトは待ってられないので ホストの台数分だけスレッドを作成します(クラスCなら256台分)。 <!-- コード --> UINT MyThreadProc(LPVOID pParam) {  CMyHost* hostData = (CMyHost*)pParam;  hostData->Get();  return 0; } void CMyDlg::OnStart() {  CMyHost hostData[hostNum];  CWinThread* pThread[HostNum];  // 台数分スレッド起動  for (int i=0;i<(int)HostNum;i++) {   hostData[i].ipAddr = NetworkAddress + (DWORD)i;   pThread[i] = ::AfxBeginThread(MyThreadProc, &hostData[i]);  }  // 何秒か待つ  HANDLE timer = CreateWaitableTimer(NULL, FALSE, NULL);  WaitForSingleObject(timer, 10000);  // returnしてないスレッドがあっても全スレッド強制終了  /* 強制終了の仕方が分からない */ <!-- コードここまで --> 強制終了させるためには各スレッドにメッセージを投げて スレッド側でそれを判定するなどでしょうか? でも通信の終わってないスレッドは通信処理の最中なのだから どうやってメッセージを受け取ればいいのか想像つかないです。 (そもそもCInternerSessionでタイムアウトの使い方がよく分からない…、 もっとスマートな方法があれば教えていただきたいです。)

  • マルチスレッド内のループについて

    こんにちは。 開発環境は VC++6.0 SDI マルチスレッドがあり、2つの処理を行う関数が書かれています。 このスレッドはダイアログボックスに配置したストップボタンを押すとフラグFALSEになりループを終了させます。 2つの関数は、int型の整数を引数にして、処理を行います。 整数はある値に達すると 0 になり永遠にループを続け、2つの処理を行います。 と言う意味合いでプログラムを書きました。(書いたつもりです) (1)この書き方ですと、for内のループが動いている時に、右上の×ボタンでダイアログを閉じると [Debug Assertion Failed!]と言う警告文が出て強制的に終了してしまいます。 ストップボタンを押してもcount=10になるまではループしています。(当然ですが・・。) そもそもマルチスレッドの中にこのような形でfor文を入れるのは間違っているのでしょうか? どのような書き方にすれば良いのでしょうか? よろしくお願い致します。 bool m_flags;//スレッド内の処理を続けるか示すフラグ UINT CabcDlg::thread(LPVOID pParam)// { CabcDlg *pInst = (CabcDlg *) pParam; while(pInst->m_flags){//ストップボタンが押されると終了する。 for (int count = 0; count<10; count++ ) { pInst->OnSend(count); //処理A pInst->OnReceive(count);//処理B } } return 0; }

  • マルチスレッドについて

    VC++を使用しています。 マルチスレッドの引数の使用法について教えてください。 int A; int B; AfxBeginThread((AFX_THREADPROC) ::WaitThread, (LPVOID)this); UINT WaitThread( LPVOID pParam ) { if(A == 0) {     … } if(A == 1) {     … } if(B == 0) {     … } if(B == 1) {     … } } のようなプログラムを作ろうとしています。 引数の受け渡し方法教えてください。 お願いします。

  • CreateThreadのエラー

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問> 何も実行しないスレッドを作成するようにコーディングしたのですが、 「error C2440: 'type cast' : '' から 'unsigned long (__stdcall *)(void *)' に変換することはできません。」 というエラーが出ました。 これは、何が原因で、解決方法はありますか? <ソース> void CMyDlg::OnButton1() { HANDLE handle; DWORD id; handle = CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&id); } void CMyDlg::ThreadFunc(void) { } <ヘッダ> void ThreadFunc(void); 宜しければご指摘お願い致します。

  • マルチスレッド

    ウインドウズプログラミングを始めて1ヶ月弱の初心者です。 色々探してみたのですが、結局良く分かりませんでした。 宜しくお願いします。 以下のリンクにおいて、 http://wisdom.sakura.ne.jp/system/winapi/win32/win143.html 1)主スレッドとは、具体的にソースファイルのどこからどこまでのことを言うのでしょうか? そもそもスレッドとは何でしょうか?関数のことでしょうか? また、タスクとは、実行ファイルと考えて良いのでしょうか? 2)副スレッド(ThreadFunc)を作成すると、主スレッド(WinMain?)と副スレッドで並列処理をするとのことですが、CPUは普通一つしかないので、実際は、主スレッド(WinMain?)と副スレッドを常に切り替えながら動作すると思います。が、ここで疑問なのですが、主スレッドと副スレッドの切り替えはいつ誰が行うのでしょうか?また、切り替えタイミング(例えば1ms毎に切り替えたいとか)は自由に設定出来るのでしょうか? 3)"マルチスレッドは親プロセスのメモリ空間を共有します" とあるのですが、これは CreateThread(NULL , 0 , ThreadFunc , (LPVOID)hWnd , 0 , &dwID) の(LPVOID)hWnd を、副スレッド(ThreadFunc)に引数として渡しているから、つまり、主スレッドと副スレッドは、(LPVOID)hWnd だけがメモリを共有する、ということでしょうか? 主スレッドと副スレッドでメモリを共有すると、どんなメリットがあるのでしょうか? 4)マルチスレッドはこういう時に使うとよい、 というような大まかな判断基準があれば教えて下さい。 分かり辛い質問で申し訳有りません。宜しくお願い致します。

  • MFCマルチスレッドについて

    MFCマルチスレッドについて COMやIOボードからの入力に応じて動作するアプリを作っています。 AfxBeginThreadにてそれぞれワーカスレッドを作成しCOMやIOから入力があれば AfxBeginThreadを呼んでいるクラスにあるメンバ関数を実行しようとしています。 AfxBeginThreadにて*thisを送り、制御関数内で、mycls->OnButton***()というような 感じで現在は作っています。(OnButton***になっているのはデバッグ用にボタンで あらかじめ作成している関数のためです。) このときに、mycls->OnButton***()は親スレッドで動いていると考えていいのですか? あくまで親スレッドのクラスのメンバ関数を制御関数が動いている子スレッドで実行 しているだけなのでしょうか? 実は、ログ表示のため制御関数の中(受信データを表示)と、mycls->OnButton***()の中 (作業結果を表示)に同じエディットコントロールへの表示部分があります。 表示部分の処理は、いったんCStringで読み込んできて最大文字数チェックを行い、 再度文字数を調節して書き直しということをやっているため、一応クリティカル セクションにはしているのですが、実際どう動いているか分からないため、やり忘れ ていることや、やってはいけないことをやってそうです。 すいませんがご教授願います。

  • VC++ スレッドからDoModalへ

    いまさらですがVC++6.0でつまづいています MFCです AdlgクラスのダイアログのOnButtonA() からXXXスレッドを起動し そのXXXスレッドではcountを+1しつづけます。 そして別のダイアログ DDD10をDoModalで起動しそのDDD10 内のTextBoxの値にcount値を反映させて表示しようとしました 下記ソース内のAfxMessageBox(tmp);ではcount値は 更新されますが DDD10ダイアログ内のテキストボックス の値が変更されません m_gui_xfr_totalはDDD10のテキストボックスにつけた メンバー名です どなたかアドバイスをお願いします void ADlg::OnButtonA() { DDD10 dlg10 ; CWinThread *pThread = AfxBeginThread(XXX_thread_entry,(LPVOID *)this); dlg10.DoModal() ; } void XXX_Thread(){ CString tmp; unsigned int count=0; DDD10 dlg10; while(1){ count++; tmp.Format("%d",count); dlg10.m_gui_xfr_total.Format(tmp); AfxMessageBox(tmp); Sleep(1000); } }

  • Threadの使い方について

    下記のコードは,OnButton5から、30回ThreadAを起動し、ThreadAからThreadBを起動する ものです。OnButton5の中にSleep(1)が有りますと、countXとcountA, countBは共に 30までカウントアップしますが、Sleep(1)がないと、countA, countBが30までカウントアップ しない事があります。 Q1) Sleep(1)を省略できる方法はありますか? void CMFCTHREADView::OnButton5(){ int i; for(i=0; i<LIMIT; i++){  //別途設定 #define LIMIT 30 if(SW_READYA==false){ //ThreadAがreadyになるのを待って起動する } SW_READYA=false; SetEvent(hEventA_start); //loop開始 InterlockedIncrement(&countX); //OnButton5 TRACE1("====countX=%d\n",countX); Sleep(1);//これがあると旨くいきます。 } } UINT ThreadA(LPVOID pParam){ int *pThis=reinterpret_cast<int*>(pParam); //pParam引数の受取方法 int aa=*pThis; while(SW_FIRST_LOOPX){ //=================================== if(WaitForSingleObject(hEventSW_A, INFINITE)){ //スタートコマンド待ち AfxMessageBox("time_over of hEventSW_A"); } ResetEvent(hEventSW_A); TRACE("ResetEvent(hEventSW_A)\n"); while(LOOP_ON){ //LOOP_ON is off by endOfTransferWAVE //======================= if(WaitForSingleObject(hEventA_start, INFINITE)){ //スタートコマンド待ち } ResetEvent(hEventA_start); countA++; if(SW_READYB==false){ //ThreadBがreadyになるのを待って起動する } SW_READYB=false; SetEvent(hEventB_start); //threadBの開始 TRACE1("countA=%d\n", countA); SW_READYA=true; //======================= } } return TRUE; } UINT ThreadB(LPVOID pParam){ int *pThis=reinterpret_cast<int*>(pParam); //pParam引数の受取方法 int aa=*pThis; while(SW_FIRST_LOOPX){ if(WaitForSingleObject(hEventSW_B, INFINITE)){ //スタートコマンド待ち } ResetEvent(hEventSW_B); TRACE("ResetEvent(hEventSW_B)\n"); while(LOOP_ON){ //LOOP_ON is off by endOfTransferWAVE if(WaitForSingleObject(hEventB_start, INFINITE)){ //スタートコマンド待ち AfxMessageBox("time_over of hEventB_start"); } ResetEvent(hEventB_start); countB++; TRACE1("countB=%d\n", countB); SW_READYB=true; } } return TRUE; } //================= 以上、宜しくお願いします。