• 締切済み

マルチスレッドに挑戦したい

<プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <目的> COMポートでバイナリデータの送受信を行う <プログラムの仕様> 1.ダイアログの「受信開始」ボタンを押す    データ受信開始の合図"0x01"を相手機器に送る 2.相手機器がデータを永遠と送信してくる 3.データを永遠と受信する 4.ダイアログの「受信終了」ボタンを押す    データ受信終了の合図"0x02"を相手機器に送る 5.相手機器がデータ送信を止める 6.受信終了 <質問> 上記のプログラム仕様を満たすには、マルチスレッドにしないといけないと思うのですが(データの送信と受信でスレッドを分ける)、具体的に何をどうすればマルチスレッドになるのか分かりません。 マルチスレッドに必要な関数、 プログラムの全体的な流れなど、 基本的な部分を教えてください。 宜しくお願いします。

みんなの回答

  • buriburi3
  • ベストアンサー率44% (353/792)
回答No.2

Win32APIのCreateThread()を呼べばスレッドが起動します。 参考書としては 「マルチスレッドプログラミング入門」ISBN:4756116825 をお勧めします。 簡単な例としては下記のような感じ スレッドを複数動作させる場合にはmutexとか必要ですが一個だけなら排他は考えなくても実害は無いと思います。 スレッドに渡すデータはローカル変数をアドレス渡ししてはいけません。 スレッドが渡された変数を参照した時点で呼び出し元の処理が終了して領域が開放されてしまっているいる可能性があります。 スタックではなくヒープのアドレスを渡すようにした方が良いです。  HANDLE threadHandle ;//スレッドハンドル  DWORD thid ;    //スレッドID  // Dataはスレッドに渡すデータ(型は何でもよい)のアドレス:必要なければNULL  threadHandle = CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadFunc,(void *)Data,0,&thid) ;  if (threadHandle == NULL) return ;  CloseHandle(threadHandle) ; // スレッドが起動したらハンドルを閉じます // スレッド動作する関数 void ThreadFunc(DATA_t *Data) // ←ポインタ変数を1個受け取れる {  ・・スレッドの処理本体:省略・・ } DATA_tは必要なら適時定義してください。 必要なければvoid *で良いです。

meeyooyoo
質問者

補足

buriburi3様、有難うございます。 ご指摘頂いた通りだと思うのですが、以下のようにコーディングしました。 OnButton()はダイアログのボタンを押すと実行されます。 void CMyDlg::OnButton() {  HANDLE hThread; //スレッドハンドル  DWORD dwThreadID; //スレッドID  DWORD Data;  hThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadFunc,&Data,0,&dwThreadID); } void ThreadFunc(DWORD *Data) { } コンパイルするとhThread = ...の行に対して以下のエラーが出ます。 error C2440: 'type cast' : '' から 'unsigned long (__stdcall *)(void *)' に変換することはできません。 スコープ内でこの名前を持つ関数でターゲット型に一致するものはありません。 何が原因でこのエラーが出るのでしょうか? 宜しければご指摘お願い致します。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

まず「永遠と」は「延々と」のつもりかな。 それで仕様を読む限りでは、相手機器も同じプログラムの中でシミュレーションするのでなければマルチスレッドは必要ないように思うけど。 マルチスレッドにしてもあまり書きやすくはないんじゃないかな。 仕様の書き方を変えると 0.ダイヤログを表示して「受信表示」ボタンを待つ 1.ダイアログの「受信開始」ボタンを押されたら    データ受信開始の合図"0x01"を相手機器に送る 2.受信待ちをする(ここで「受信終了」ボタンも待つ) 3.データを受信する(2と繰り返し) 4.ダイアログの「受信終了」ボタンを押されたら    データ受信終了の合図"0x02"を相手機器に送る 5.相手機器がデータ送信を止めたことを確認する(?) 6.受信終了 ですね。(5は必要ないかも) ここで必要なのは、2でCOMポートの受信と「受信終了」ボタンを同時に待つ複数待ちです。これはWIN32APIだとMsgWaitForMultipleObjects等が使えますし、コンソールアプリケーションではselect等も使えますが、MFCでのやり方は覚えてません。 COMポート通信を非同期アクセスにする必要があるかも。

関連するQ&A

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

    こんにちは。 開発環境は 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; }

  • マルチスレッドにする必要がありますか?

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース シングルスレッド <目的のプログラム仕様> ・ダイアログのボタンを押すとOnボタン関数に入る ・Onボタン関数で関数1(無限ループ)と関数2(無限ループ)を実行する ・関数1はnDataの内容を更新し続ける(37回/sec) ・関数2はnDataの内容を基に、数秒かかる処理を10秒毎に行う <今の知識で出来るコーディング> void Onボタン関数(){  int nData[10];  関数1(nData);  関数2(nData); } void 関数1(int nData[]){  for(;;) for(int i=0;i<10;i++) nData[i] = 更新データ; } void 関数2(int nData[]){  int nTotal=0;  DWORD dwOldTime = clock();  for(;;){   if(clock() - dwOldTime >10000){//10秒経過で実行    dwOldTime = clock();    for(int i=0;i<10;i++) nTotal += nData[i];//実際は数秒かかる程の処理    nTotal = 0; //初期化   }  } } <問題点> 今の知識で出来るコーディングでは、関数1の無限ループから処理が 他へ移ることは無く、関数2を実行する事が出来ません。 関数2の合計を計算する処理は、実際には数秒かかるので、 関数1で関数2を呼び出すことが出来ません。 (関数1は37回/secでデータ更新しなければならないので) <質問> 目的のプログラム仕様を満たすには、マルチスレッドにしなければ ならないでしょうか? シングルスレッド、マルチスレッド、どちらの方法でも良いので、 どのようにコーディングすれば良いのか教えて下さい。 宜しければ、ご指摘お願い致します。

  • C# マルチスレッドにおける例外処理

    下記のようなデリゲートを利用したマルチスレッドのプログラムを組みました。 しかし、マルチスレッド内で例外がおきても、正常にプログラムが終了してしまいます。 (try-catchでも例外を捕捉できません) マルチスレッドプログラムにおいて、例外を捕捉するにはどうすれば、いいのでしょうか? using System; using System.Threading; class Class1 { delegate void delg(); public static void Main() { delg d = new delg(multi); d.BeginInvoke(new AsyncCallback(call), null); //マルチスレッド開始 System.Threading.Thread.Sleep(500); //マルチスレッドで例外を強制的に投げているので、 //ここまでたどり着く前にアプリケーションが落ちるはず。 //しかし、実際には正常終了。 Console.WriteLine("メインメソッド 正常終了"); } public static void multi() { Console.WriteLine("マルチスレッドで実行中"); throw new Exception(); //例外を強制的に投げる。 } public static void call(IAsyncResult ar) { Console.WriteLine("コールバックメソッド実行"); } }

  • ボタンが押された事を検知するには?

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <目的> 1.ダイアログにボタン1を配置する 2.処理A(無限ループ)を開始する 3.処理Aの先頭でボタン1が押されたか判断する 4.ボタン1が押された場合処理Aを終了し、処理Bを行う というプログラムを作成する。 <質問> 目的のプログラムを作成するには、ボタン1が押された事を検知する 必要があると思うのですが、その方法が分かりません。 ボタンが押された事を検知するにはどうしたら良いのでしょうか? 宜しければご指摘お願い致します。

  • マルチスレッド化。

    今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

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

    現在”猫でもできる”の87、88章を学んでおります。 まず87章でマルチスレッドの根本的なやり方を学びましたが、いきなり疑問が浮かびました。 _beginthread関数によりスレッドをスタートさせ、この関数で登録した関数内で_endthread関数を実行し終了させていることは分かります。 しかし_beginthread関数で登録した関数に引数を渡す処理がどの部分で行われているのかわかりません。 登録する関数はvoid型で引数はvoid*型でなければいけないことは分かったのですが、プログラムのどこを見てもこの登録した関数に引数を渡す処理が行われていません。 その辺の動作の説明を分かる方でいいのでよろしくお願いします。 そして88章では排他制御のマルチスレッドを行うプログラムの製作を行っているのですが、ちょっとした疑問が浮かびました。 EnterCriticalSection関数、LeaveCriticalSection関数ではさまれたプログラムは排他制御され他からアクセスされない。 この関数はこんな理解で良いんですかね? この理解で行くと、88章で説明していきますが、子ウィンドウを2つ作成しそれぞれのプロシージャ内で排他制御された関数をスレッドとしてスタートしています。 この2つのスレッドの動作についてですが、互いに排他制御関数が記述されているため、動作としてはまず左の子ウィンドウのスレッドが処理されている場合、右の子ウィンドウのスレッドは停止している。そして左の子ウィンドウのスレッドの排他制御が解放されたときに、右の子ウィンドウのスレッドが開始する。 そしてあるとき左の子ウィンドウのクライアントウィンドウ内で右クリックされた場合、その時点で排他制御されたスレッドが終了するのを待ち、終了したらcountを+1する。 こんな動作が行なわれていると理解してよいのでしょうか?

  • マルチスレッドでブレイクポイントするとフリーズする

    C++/CLI .Net2008 windowsフォームアプリケーション 二つのスレッドが同時に動いているマルチスレッドプログラムを作成しています。 デバッグでブレイクポイントを張って途中で止めたいのですが、止めてすぐもしくはF10で2,3行進めるとフリーズしてアプリが動かなくなってしまいます。他のoutlook等も動かせず、タスクマネージャも開かないため、画面下のウィンドウを右クリック、閉じるを5~10分くらいかけて行って終了させています。たまにVisualStudio自体もフリーズして落ちることがあります。 ブレイクポイントで止めなければフリーズはしません。 プログラムの構成としては、 片方は外部装置からリアルタイムでデータを受信し、判別した結果を出力するスレッドと、その判別結果を元に状態を遷移させるスレッドです。 また、状態によってはタイマーを設けている箇所があり、タイマー処理もスレッドで行っています。 ブレイク張らずに実行した時におかしい動作をしている箇所があるので1行ずつ見たいのですが、マルチスレッド環境ではフリーズするものなのでしょうか?

  • UDPで受信終了の合図を出して受信終了させる

    UDPの帯域測定プログラムを作成しています。 100個のパケットを受信した後、受信処理を終了させるのに、 endの文字を挿入したパケットを受信することで受信を終わらせようと考えています。 パケットを送信する側は100個のパケットを送信し終えたら、endのパケットを送信します。 受信側はendのパケットを受信したら受信を終了します。 受信側がendを受信したら送信側がendのパケットを送信するのを止めさせたいのです。 UDPではパケットが消失するため、送信側は受信側がendを受け取ったことを確認したあとに送信をやめなければなりません。 endを受け取ったら、合図を返信すればよいと思いますが、その合図が消失することもあるので、「endを受信したら合図を返信する」という処理を終わらせるタイミングも分かりません。 どのようにしてendを受け取ったことを確認すればよいでしょうか?

    • ベストアンサー
    • Java
  • 受信中に終了してしまいます

    Outlook Express 5を使ってます。ある日突然、送受信ボタンを押し、受信を開始するとソフトが終了するようになってしまいました。ちなみに送信ボタンを使えば送信はできます。変なものを受信しようとしているのでしょうか?どうにもなりません。助けてください。

  • エラー!!

    MFCでプログラムを組んだのですがエラーが出て困っています…。 でも、処理内容はちゃんと行ってくれるのです。内容としてはダイアログ上に設定情報を入力できるテキストボックスと実行の合図となる実行ボタン、ダイアログを閉じる(プログラムを終了させる)キャンセルボタンからなっています。テキストボックスに条件を打ち込み実行ボタンを押すとその条件に従って処理するわけです。ここは問題なく動いています。 ところが問題はキャンセルボタンを押したときなのです。ダイアログを閉じる文は次のものです。 CDialog::OnCancel(); これで閉じれるのですが、その後に次のようなエラーが出ます!しかも2回…。ちなみにMFcalculation.exeというのは私のプログラム名です。 「問題が発生したため、MFcalculation.exe を終了し ます。 ご不便をおかけして申し訳ありません。」 私の予想では処理をしようとしたときのエラーではなくダイアログ自体を閉じようとしている時にエラーが起きてるように思うんですが。非常にわかりにくいとは思いますが何か思い当たることがあれば何でもいいので教えてください。