• ベストアンサー

WaitForMultipleObjects関数の待機状態から抜けるにはどうすればいいのですか。

初心者です。XPとVC++ 6.0で開発しています。 シリアル通信プログラムを作成しておりますが、クロスケーブルでPC同士をつないで、片方はハイパーターミナル(以下H)を立ち上げて、もう片方は、作成しているプログラム(以下P)を走らせて通信しようとしています。Pから、Hへの送信はできるのですが、Hを走らせているPCのキーボードをたたいても、Pで受信ができません。WaitForMultipleObjects関数のところで待機状態になったままです。DEBUGの進め方についてアドバイスをいただけますでしょうか。 Pを実行した際には、GetLastError関数がERROR_IO_PENDINGを返しており、IOからのデータ待機状態に入っています。(※P,H共に、COM1,9600bps,8bit,NONEに設定しています。)ご教示お願いいたします。 // PURPOSE: This is the starting point for the Read Thread. DWORD WINAPI StartReadThreadProc(LPVOID lpvParam) { char szInputBuffer[INPUTBUFFERSIZE]; DWORD nNumberOfBytesRead; HANDLE HandlesToWaitFor[3]; DWORD dwHandleSignaled; DWORD fdwEvtMask; OVERLAPPED overlappedRead = {0, 0, 0, 0, NULL}; OVERLAPPED overlappedCommEvent = {0, 0, 0, 0, NULL}; overlappedRead.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); overlappedCommEvent.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); // We will be waiting on these objects. このイベントが立つまでRX動作は待機状態になる。 HandlesToWaitFor[0] = g_hCloseEvent1; HandlesToWaitFor[1] = overlappedCommEvent.hEvent; HandlesToWaitFor[2] = overlappedRead.hEvent; // Keep looping until we break out. while (TRUE) { // Wait until some event occurs (data to read; error; stopping). dwHandleSignaled = WaitForMultipleObjects(3,HandlesToWaitFor, FALSE, INFINITE); switch(dwHandleSignaled) { case WAIT_OBJECT_0: // Signal to end the thread. { // Time to exit. } case WAIT_OBJECT_0 + 1: // CommEvent signaled. { // Handle the CommEvent. // Start waiting for the next CommEvent. break; } case WAIT_OBJECT_0 + 2: // Read Event signaled. { // Get the new data! break; } case WAIT_FAILED: // Wait failed. Shouldn't happen. { goto EndReadThread; } default: // This case should never occur. { OutputDebugString("Unexpected Wait return value"); goto EndReadThread; } } // End of switch(dwHandleSignaled). } // End of while(TRUE) loop. // Time to clean up Read Thread. EndReadThread: OutputDebugString("Read thread shutting down\n"); PurgeComm(g_hCommFile1, PURGE_RXABORT | PURGE_RXCLEAR); CloseHandle(overlappedRead.hEvent); CloseHandle(overlappedCommEvent.hEvent); g_dwReadThreadID1 = 0; CloseHandle(g_hReadThread1); g_hReadThread1 = 0; return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.4

見た目はOKですね。 イベントハンドルが渡っているなら、通信エラーが考えられます。 ACEにどんな設定をしたか、調べてみて下さい。 http://www.ys-labo.com/BCB/2007/070512%20RS232C%20zenpan.html http://members.jcom.home.ne.jp/0434383301/vc10.htm いきなりではなく、先ず1バイトの送受信を割り込みでなく、 普通に実行してみましょう。

cpptext
質問者

お礼

nda23様 ご返答有難うございます。 一歩一歩確認していきます。 ご教示ありがとうございました。

その他の回答 (3)

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.3

う~ん・・・ 初心者にマルチスレッドの同期制御はハッキリ言って荷が 重過ぎますね。スレッドだとか同期だとか聞いてピンときますか? とりあえず、次の点を調べてみて下さい。 (1)CreateFile FILE_FLAG_OVERLAPPED が指定されていますか? (2)ReadFile 第5パラメータのhEventメンバに作成したイベントがセットされて いますか? いずれも指定通りなら、イベントが発生するはずです。 >goto EndReadThread こういうコーディングを見ると、コメントのしようがありません。 さいとう たかを のマンガではないけど、「・・・」です。 大変な仕事を引き受けられたご様子、お察し申し上げます。

cpptext
質問者

補足

nda23様 アドバイスありがとうございます。 もう脳みそがゆでだこ状態です。オーバーヒート気味です(笑)カーニハン,リッチーのプログラミング言語Cから初めて、ただいまVC++に足を突っ込んでいます。 CreatFile, ReadFileについては、下記の様に作成されており問題ないようです。 (1)hComm = CreateFile( port,GENERIC_READ | GENERIC_WRITE,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); (2)ReadFile(g_hCommFile1,lpszInputBuffer, dwSizeofBuffer,lpnNumberOfBytesRead, lpOverlappedRead) PARAMETERSの説明・・・ // lpOverlappedRead - address of overlapped structure to use. // lpszInputBuffer - Buffer to place incoming bytes. // dwSizeofBuffer - size of lpszInputBuffer. </code></pre> // lpnNumberOfBytesRead - address of DWORD to place the number of read bytes. イベントが発生すれば、プログラムはWaitForMultipleObjects関数から次のステップに進むはずですよね?この関数の最後の引数を1000(ms)とかにすると、ちゃんとWAIT_TIMEOUTで抜けて、イベントが発生していないことは確認できました。そもそものパリティの設定がおかしいのかとも思いましたが、送信はできていましたし、NONEにしてもEVENにしても受信できませんでした。他に何を検証したらよろしいでしょうか・・・。 ※あと、SetCommMaskもSetupCommEventとSetupReadEventの前に設定さていました。 // Setup CommEvent handling. // Set the comm mask so we receive error signals. if (!SetCommMask(g_hCommFile1, EV_ERR)) { OutputDebugString("Unable to SetCommMask: "); goto EndReadThread; } どうやらこちらのサイトのものとそっくりなようです。↓ http://topic.csdn.net/t/20010420/16/101329.html

  • chie65535
  • ベストアンサー率43% (8519/19367)
回答No.2

>overlappedCommEvent.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); でシリアルからデータが来た場合にイベントが立つんじゃないんでしょうか? 「シリアルからデータが来た場合にイベントが立つ」んじゃなくて「シリアルからデータが来た場合に『自分で』イベントを立てなきゃならない」のです。 イベントを立てるには「SetEvent()を使う」ので、必ず、受信ルーチンのソースのどこかにSetEvent()がある筈です。 もし、SetEvent()が無いのであれば「質問者さん自身が、必要な場所に的確にSetEvent()を書き加えなければならない」ので、自分で書き加えましょう。

cpptext
質問者

補足

chie65535様、nda23様 失礼致しました。プログラムが長かったので、はしょった部分に、下記の処理が入ってました。 一応非同期通信に必要?なWaitCommEventとReadFile関数が入ってました。SetCommMask関数が入っていなかったのですがこれも必要でしょうか? HandlesToWaitFor[2] = overlappedRead.hEvent; * * // Setup CommEvent handling. // Start waiting for CommEvents (Errors) if (!SetupCommEvent(&overlappedCommEvent, &fdwEvtMask)) //SetupCommEvent内部でWaitCommEvent関数を設定しています。 { goto EndReadThread; } // Start waiting for Read events. if (!SetupReadEvent(&overlappedRead, //SetupReadEvent内部でReadFile関数を設定しています。 szInputBuffer, INPUTBUFFERSIZE, &nNumberOfBytesRead)) { goto EndReadThread; } * * // Keep looping until we break out. while (TRUE)

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.1

ところで、誰がイベントをシグナル状態にするんですか? 誰も何もしていないような気がします。 普通は受信割り込み処理の中でSetEventします。

cpptext
質問者

補足

えーと、退職した前任者からのひきつぎなので、勉強しながらのプログラミングなのですが、overlappedCommEvent.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); でシリアルからデータが来た場合にイベントが立つんじゃないんでしょうか? 接続先のPCのキーボードをたたいて、データが飛んできて、それに反応する割り込み処理?が必要なのでしょうか。 すみません、勉強しながらなので、いまいちシーケンスの深い理解が得られておりません。

関連するQ&A

  • マルチスレッドプログラミングについて

    マルチスレッドプログラミングについていくつか教えて下さい。 マルチスレッドの基礎がまだ分かってないので初心者でも分かり易いようにお願いします。 1:イベントオブジェクトについて教えて下さい。 「イベントオブジェクト」の概念がよく分かりません。 ○シグナル状態と非シグナル状態とはどういう状態なのでしょうか? ○自動リセットの場合ではどのタイミングで切り替わっているのでしょうか?(下記のソースの場合) ○手動リセットの場合ではどのタイミングで切り替えればよいのでしょうか?(下記のソースの場合) 2:CloseHandle() と ExitThread() について教えて下さい。 ○この2つの関数の役割の違いについて教えて下さい。 「スレッドハンドルを閉じる=スレッドを終了」ではないのでしょうか? また、これらの関数実行時にシグナル状態は気にする必要はありますか?(シグナル状態にしなくてよいのか?) 下記のソースは簡略化のためかなり省略されています。 DWORD WINAPI ThreadProc( DWORD i ) { while( true ) { DWORD r = WaitForMultipleObjects( 2, hEvent, FALSE, INFINITE ); if( r == WAIT_OBJECT_0 ) { // 処理1 } else if( r == WAIT_OBJECT_0 ) { // 処理2 } else { ExitThread( TRUE ); // スレッド終了 } } } void MainProc() { // 自動リセットのイベントオブジェクト作成 for( int i=0; i<2; i++ ) { hEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); } // スレッドを作成 hThread = CreateThread( NULL, 0, ThreadProc, NULL, 0, &dwThreadID ); }

  • C++ GUIのメッセージループ。

    初心者です。 よろしくお願いします。 とても重く時間の掛かる処理を色んなサイトを参考にスレッドにしてみたんですけど、書き方が悪いのか、再描写がワンテンポ遅れたり、アプリケーションを複数起動したりするとフリーズしてしまったりします。 原因はメッセージループにあるような気がしてるんですが、この書き方はおかしいですか?? どのサイトから引用したのかわからなくなってしまいました。 気付いたことなどあったら何でもいいので教えて貰えたら嬉しいです!よろしくお願いします!! thread01に重い処理が書かれてます。 int thread_call() {   unsigned int dwThreadId[1];   HANDLE hThread[0] = (HANDLE)_beginthreadex(     NULL,     0,     ( unsigned int (__stdcall*)(void*) )thread01,     NULL,     0,     &dwThreadId[0] );   MSG msg;   DWORD dwRet = WAIT_TIMEOUT;   while ( 1 ) {     dwRet = ::MsgWaitForMultipleObjects( sL, hThread, FALSE, INFINITE, QS_ALLEVENTS );     if ( dwRet == WAIT_OBJECT_0 + sL ) {       if ( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {         ::TranslateMessage( &msg );         ::DispatchMessage( &msg );       }     } else if ( dwRet >= WAIT_OBJECT_0 && dwRet < WAIT_OBJECT_0 + sL )       break;   }   CloseHandle( hThread[0] );   hThread[0] = NULL; }

  • CloseHandle()

    スレッドを、同じハンドルを利用して作る場合、 途中でハンドルの開放が必要か教えてください。 void thread1(); HANDLE handle; //スレッド作成 handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread1, NULL, 0, &dwID); //作ったスレッドの終了を待つ WaitForMultipleObjects(1, handle, TRUE, INFINITE); //スレッドを作った時のハンドルを閉じる。これ必要? CloseHandle(handle); //同じハンドルを利用して別のスレッドであるthread2を作成 handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread2, NULL, 0, &dwID); この、CloseHandle(handle);は必要ですか?

  • スレッドについて

    スレッドについて勉強中なのですが、簡単なスレッド作り、 スレッドの処理が終わってからメインの処理を行わせたくて 以下のようなプログラムを書いてみました。 そこで、WaitForSingleObjectを使ってスレッドが終了するのを 待ちたいのですが、WaitForSingleObjectではまってしまうようで sprintfのメッセージ(スレッドが止まってしまっている)が 表示されません。 WRITE関数の処理が終われば、、WaitForSingleObjectで処理が 戻ってくると考えているのですが…。 スレッドについてと、間違いについて教えてもらえないでしょうか? 宜しくお願いします。 main { if(!stop) {   File = CreateFile(...); g_hThead = CreateThread(NULL,0,WRITE,(LPVOID)NULL,0,NULL); g_stop = false; }else { g_stop = true; ::WaitForSingleObject(g_hThead, INFINITE); CloseHandle(File); CloseHandle(hThead ); } } void WRITE() { while(!g_stop) { WriteFile(...); } ...処理を行う sprintf("スレッドを終了します。") }

  • マルチスレッドプログラム

    いつもお世話になっております。 今回はマルチスレッドプログラムについてお聞きしたいです。 マルチコアCPUを使ってたとえば下記のようなことをしたいときに for (int i = 0; i < 1000000; i++) { sum += i; } このまま計算するよりもいくつかスレッドを作って、計算量を分散させてから最後に足してやるほうが早いと思いまして、 現在Core2Quadが手元にありましたのでスレッドを4つ作って スレッド1で0から250000まで スレッド2で250001から500000まで スレッド3と4も同様にして実際にやってみたのですが スレッドなしの状態よりも倍くらい時間がかかってしまうようになってしまいました。 計算結果は同じになり、CPU使用率もシングル時が25%、マルチ時が100%になっているので意図したようにはできていると思います。 GetProcessAffinityMaskを使って、各スレッドにひとつづつコアを割り当てても同様でした。 実際に時間が4分の1に近くなると思っていたのですが2倍かかってしまったので不思議です。 どなたか上記のことを思惑通りに動かせそうな方法をご存知の方はご教授願います。 プログラムは全部は無理ですが重要そうなところは下記のとおりです。 スレッド作成部分 {   DWORD dwStart = ::timeGetTime();   _thread_handle[0] = (HANDLE)::_beginthreadex(NULL, 0, thread_first, NULL, CREATE_SUSPENDED, &_thread_first_id);   _thread_handle[1] = (HANDLE)::_beginthreadex(NULL, 0, thread_second, NULL, CREATE_SUSPENDED, &_thread_second_id);   _thread_handle[2] = (HANDLE)::_beginthreadex(NULL, 0, thread_third, NULL, CREATE_SUSPENDED, &_thread_third_id);   _thread_handle[3] = (HANDLE)::_beginthreadex(NULL, 0, thread_forth, NULL, CREATE_SUSPENDED, &_thread_forth_id);   for (int num = 0; num < 4; num++)   {     ::ResumeThread(_thread_handle[num]);   }   ::WaitForMultipleObjects(4, _thread_handle, TRUE, INFINITE);   for (num = 0; num < 4; num++)   {     ::CloseHandle(_thread_handle[num]);   }   DWORD dwEnd = ::timeGetTime(); } 各スレッド部分 { HANDLE hCurrent = ::GetCurrentProcess(); DWORD pamask, samask, patmp = 0; int nRet = ::SetProcessAffinityMask(hCurrent, 0x0001); ::GetProcessAffinityMask(hCurrent, &pamask, &samask); DWORD dwStart = ::timeGetTime(); _result1 = 0; for (int multi = 0; multi < _multi; multi++) {   for (DWORD i = 0; i < 100000/4; i++)   {     _result1 += i;   } } DWORD dwEnd = ::timeGetTime(); time1 = dwEnd - dwStart; ::_endthread(); return 0; } 開発環境は WindowsXP SP3 VisualStudio6.0 ATL/WTLです。

  • バイナリを16進数で表示したい

    VC++6.0,MFC,ダイアログベースでバイナリデータ受信とファイル書き込みのプログラムを作っています。 COMポートからバイナリを10バイト受信し、受信した内容を1.txtに書き込み、1.txtを開いて、受信した内容を確認したいです。 以下のソースで実行すると、1.txtにはFフフフフフフフフフと書かれていました。これを16進数で表示させたり、10進数で表示させるにはどうしたらいいでしょうか? /////////データ受信////////////// unsigned char rdBuf[10]; unsigned char* prdBuf; DWORD dwCount; DWORD dwRead; prdBuf = &rdBuf[0]; dwCount = 10; if(ReadFile(hCom,prdBuf,dwCount,&dwRead,&old) == 0){ if(ERROR_IO_PENDING == GetLastError()){ if(WaitForSingleObject(hEvent,INFINITE) == WAIT_OBJECT_0){ if(GetOverlappedResult(hCom,&old,&dwCount,TRUE)){ //"データ受信完了" }}} else //エラー } /////////ファイルに書き込む////////////// HANDLE hFile; hFile = CreateFile( ".\\ScanData\\1.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL ); if(WriteFile( hFile, rdBuf,10, &wbyte, &old ) == 0){ if(ERROR_IO_PENDING == GetLastError()){ if(WaitForSingleObject(hEvent,INFINITE)==WAIT_OBJECT_0){ if(GetOverlappedResult(hCom,&old,&wbyte,TRUE)){ //書き込み完了 }}} else //書き込み失敗 }

  • スレッドの終了を知りたい(WindowsAPI)

    CreateThread()で作成したスレッドの終了を知りたい (具体的には、スレッドが終了するまで待機したい)のですが、 うまくいかず困っています。WindowsAPIに関する本やネットで調べた ところ、WaitForSingleObject()が適用できると考え、 以下のようなプログラムを作成したのですが、 元のスレッドがWaitForSingleObject()のところで 止まると同時に、CreateThread()で作成されたThread_1()も 止まってしまいます。アドバイスいただけますでしょうか。 ----プログラム(該当部分)ここから---- DWORD Thread_1(LPVOID param) {  int i;  char buff[128];  /* iが99のときのみ終了してよい */  while(g_iFlg == 1)  {   for(i = 0; i < 100; i++)   {    Sleep(100);    wsprintf(buff, "%d", i);    SetDlgItemText((HWND)param, IDC_STATIC_1, buff);   }  }  ExitThread(0);  return 0; } BOOL CALLBACK Proc_2(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {  switch(uMsg)  {   case WM_INITDIALOG:    g_iFlg = 1;    g_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread_1, (LPVOID)hDlg, 0, &g_dwThread);    return TRUE;   case WM_COMMAND:    switch(LOWORD(wParam))    {     case IDC_BUTTON_CANCEL:     case IDCANCEL:      g_iFlg = 0;      WaitForSingleObject(g_hThread, INFINITE);      CloseHandle(g_hThread);      EndDialog(hDlg, 0);      return TRUE;    }  }  return FALSE; } ----プログラム(該当部分)ここまで----

  • 非同期のプロセス間通信(パイプ)で全データ受信する

    こんにちは。 非同期のプロセス間通信(パイプ)で詰まっています。 環境はWindowsで処理系はC++(Win32)です。 スレッドを用意して、 hPipe = ::CreateFile( L"\\\\.\\pipe\\pipename", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ) ; で作成し、OVERLAPPED構造体を // ZeroMemory( &so, sizeof( OVERLAPPED )) ; sOverlapped.hEvent = ::CreateEvent( NULL, FALSE, FALSE, NULL ) ; として、 const size_t bufsize = 16 ; BYTE     buffer[ uBufSize ] ; DWORD    dwNumberOfBytesRead ; bRet = ::ReadFile( hPipe, buffer, bufsize, &dwNumberOfBytesRead, &so ) ; で読み込みをしています。ReadFile関数はすぐ戻りbRetはFALSEで返ってくるため、GetLastErrorを調べて、 switch( ::GetLastError()) {   case ERROR_IO_PENDING :     bRet = ::GetOverlappedResult( hPipe, &so, &dwNumberOfBytesRead, FALSE ) ;     break ; } としてWaitForMultipleObjectsでsOverlapped.hEventがシグナル状態になったら取得したデータの処理をしています。 シグナル状態になるならないに関わらず、上記のReadFileとGetOverlappedResultはループでぐるぐる回しています。 上記の状態で短いデータならよかったのですが、上記のReadFileで読み込み最大サイズの16バイトを超えてしまとうと、 残りの部分のみしか取得できませんでした。 0123456789ABCDEFabcdefg というデータを受信しようとしたとき、後半のabcdefgだけしか取得できませんでした。 すべてのデータを正しく取得するにはどのようにしたらよいのでしょうか?

  • ReadFileでエラーが出ます。

    シリアルポートで非同期でバイナリを受信するプログラムを作成しています。 受信部分は以下のソースです。これで実行すると「データ受信エラー」のダイアログが出ます。 GetLastErrorでは998(メモリ ロケーションへのアクセスが無効です。)が得られました。 ネットで調べましたが何が原因かも分かりません・・。 どうかアドバイスお願いします。 HANDLE hEvent; hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); OVERLAPPED old; ZeroMemory( &old, sizeof(old) ); old.Offset = 0; old.OffsetHigh = 0; old.hEvent = hEvent; DWORD dwCount; char* rdBuf; DWORD dwRead; if(!ReadFile(hCom,rdBuf,dwCount,&dwRead,&old)){ if(ERROR_IO_PENDING == GetLastError()){ GetOverlappedResult(hCom,&old,&dwRead,TRUE); } else MessageBox("データ受信エラー","試作1",MB_ICONSTOP); }

  • マルチスレッドプログラミングについて

    こんばんわ。 マルチスレッドプログラミングを行なっています。開発環境はVC++.NET2003でC言語を用いてコンソールアプリケーションを勉強中です。 以下にプログラムを示します。 以下のプログラムは、 (1)ThAとThBが交互に1~10までカウントUP (2)ThBだけが11~20までカウントUP (3)ThAはTh11から、ThBは21からカウントUP というプログラムを記述したつもりなのですが・・・実行開始後は(1)から(3)のように表示できるのですが、それ以降はThAとThBが交互に表示されてしまいます。 (1)から(3)を繰り返す記述の仕方はありますでしょうか? よろしくお願い致します。 HANDLE hEvent[3]; unsigned __stdcall ThB(void *lpx){ int j; int l=1; for(j=1;j<100;j++){ Sleep(100); printf("ThB%d\n",j); if(l%20==0){ SetEvent(hEvent[0]); } l++; } return 0; } unsigned __stdcall ThA(void *lpx){ int k; int j=1; for(k=1;k<100;k++){ Sleep(100); printf("ThA%d\n",k); if(j%10==0){ WaitForSingleObject(hEvent[0],INFINITE); } j++; } SetEvent(hEvent[2]); return 0; } int main(int argc ,char *argv[]){ unsigned int thID[2]; HANDLE hTh[2]; int i; hEvent[0] = CreateEvent(NULL, TRUE, FALSE, "CH0"); hEvent[1] = CreateEvent(NULL, TRUE, FALSE, "CH1"); hEvent[2] = CreateEvent(NULL, TRUE, FALSE, "MAINEVENT"); hTh[0] = (HANDLE)_beginthreadex(NULL, 0, ThA, NULL, 0, &thID[0]); hTh[1] = (HANDLE)_beginthreadex(NULL, 0, ThB, NULL, 0, &thID[1]); WaitForSingleObject(hEvent[2], INFINITE); for(i=0;i<2;i++) CloseHandle(hTh[i]); return 0; }

専門家に質問してみよう