• ベストアンサー

Mutexの次の使い方で

typedef struct{ HWND hwnd;BOOL th_end;HANDLE hmutex; } DATA, *PDATA; /////////////////////////////////////// static HANDLE hThread1,hThread2; DWORD threadID1,threadID2; static DATA data; static HANDLE hMutex; switch (msg) { case WM_CREATE: //hMutex= //CreateMutex(NULL,FALSE,NULL); data.hwnd = hWnd; data.th_end = FALSE; data.hmutex = hMutex; hThread1=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Thread1, (LPVOID)&data, 0,(LPDWORD)&threadID1); hThread2=CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)Thread2, (LPVOID)&data, 0,(LPDWORD)&threadID2); /*x*/hMutex= /*x*/CreateMutex(NULL,FALSE,NULL); break; とするのは正しくて/*x*/の行を削除して//をとり hMutexの位置を前に持ってくるのは間違っているのでしょうか?

  • nubou
  • お礼率62% (293/470)

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

  • ベストアンサー
回答No.4

> エラーもでず動作の違いも峻別できませんでした Thread内のWaitForSingleObject()で失敗している と思われますが、このサンプルでは戻り値のチェック を行なっていません。スレッド間でリソースの競合が 発生していると思われます。

nubou
質問者

お礼

ありがとうございます どうもおかしいと思っていたので助かりました

nubou
質問者

補足

#include <string> using namespace std; int i_th1,i_th2; を追加しThread1&Thread2を DWORD WINAPI Thread1(LPVOID pparam) { PDATA pdata; HDC hdc; string str; char s[99]; pdata = (PDATA)pparam; while (!pdata->th_end) { WaitForSingleObject(pdata->hmutex, INFINITE); hdc = GetDC(pdata->hwnd); str="スレッド1:";str+=itoa(++i_th1,s,10); TextOut(hdc,0,0,str.c_str(), str.size()); Sleep(500); ReleaseDC(pdata->hwnd, hdc); ReleaseMutex(pdata->hmutex); } return 0L; } DWORD WINAPI Thread2(LPVOID pparam) { PDATA pdata; HDC hdc; string str; char s[99]; pdata = (PDATA)pparam; while (!pdata->th_end) { WaitForSingleObject(pdata->hmutex, INFINITE); hdc = GetDC(pdata->hwnd); str="スレッド2:";str+=itoa(++i_th2,s,10); TextOut(hdc,0,20,str.c_str(), str.size()); ReleaseDC(pdata->hwnd, hdc); ReleaseMutex(pdata->hmutex); } return 0L; } と変更したところ 後ろに宣言していたのではi_th1に対してi_th2が桁違いに大きくなっていきますが 前に宣言したらi_th1とi_th2はせいぜい1つ違いを保ちます ということで作者のケアレスミスだと思われます どうもありがとうございました

その他の回答 (4)

  • nabezo-
  • ベストアンサー率50% (2/4)
回答No.5

何回か質問を読み返しましたが、やっぱり私も何を目的とした質問か理解に苦しみます。。。 一応、回答しますが。。。 「HANDLE hMutex」と変数を宣言しただけでは何にも使えません。 CreateMutexで初めて有効な値を取得できます。その後、その値を使って排他などの制御できるようになります。 スレッドの方では渡されたDATA構造体のポインタを使用して排他制御しようとしているのか、変数がグローバールの値で、それを使用しているのかわかりませんが、どちらにしても最後にCreateMutexを行うのはロジック的にも理解できません。 あと、最後にCreateMutexして、グローバル変数のhMutexに代入し、各スレッドではその値を直接使っている場合だとしても、各スレッドの参照処理より前にCreateMutexが実行される保障はないのでご注意を。 タスクスイッチのタイミングによっては各スレッドの参照処理が先に動作することもあります。 CreateThreadの第5パラメータで、スレッドをサスペンドする必要性なども考慮する必要があります。

nubou
質問者

お礼

ありがとうございます できれば http://www.kumei.ne.jp/c_lang/sdk/sdk_92.htm をアドレスにいて手見てミューテックスの宣言の部分を見ていただきたいのですが・・・ セカンドオピニオンを得られれば鬼に金棒ですから よろしくお願いします

回答No.3

> CreateMutex 関数が返すハンドルには...ミューテックスオブジェクトのハンドルを要求する任意の関数で使うことができます。 裏を返せば、CreateMutex(あるいはOpenMutex)で得られたハンドルでなければ使えませんね。 > Mutexは宣言するだけでクリエイトしなくても使えるのか やってみました?

nubou
質問者

補足

ありがとうございます もちろんやってみました 動作を見ていても特に違いが分からないのです http://www.kumei.ne.jp/c_lang/sdk/sdk_92.htm にかかれているソースをBoralnd C++5.5 でコンパイルし実行してみましたがエラーもでず動作の違いも峻別できませんでした

回答No.2

> Mutexは宣言するだけでクリエイトしなくても使えるのか > どうかということが分からないのです ...マニュアルには何と書かれているでしょうか?

nubou
質問者

補足

ありがとうございます マニュアルには以下のようにかかれています 読解力と予備知識が欠如しているので関連部分について抽出し解説していただければ幸いです CreateMutex 関数が返すハンドルには、新しいミューテックスオブジェクトへの MUTEX_ALL_ACCESS アクセス権が割り当てられていて、ミューテックスオブジェクトのハンドルを要求する任意の関数で使うことができます。 呼び出し側プロセスの任意のスレッドは、「wait functions」(待機関数)を呼び出す際に、ミューテックスオブジェクトのハンドルを指定できます。単一オブジェクトの待機関数は、指定されたオブジェクトがシグナル状態になると制御を返します。複数オブジェクトの待機関数に対して、指定されたオブジェクトの 1 つ(またはすべて)シグナル状態になったときに、制御を返すよう指示できます。待機関数が制御を返すと、待機中のスレッドは解放され、実行が継続されます。 ミューテックスオブジェクトは、どのスレッドにも所有されていない場合はシグナル状態になります。作成側スレッドは、bInitialOwner パラメータを使うと、既存のミューテックスの所有権を即座に要求できます。ミューテックスがスレッドに所有されている場合は非シグナル状態になり、呼び出し側スレッドがそのミューテックスの所有権を要求するには待機関数(WaitForSingleObject など)を使わなければなりません。その状態でミューテックスがシグナル状態になると、待機スレッドの 1 つに所有権が割り当てられ、そのミューテックスは非シグナル状態へ変化し、待機関数は制御を返します。特定のミューテックスを所有できるスレッドは、一度に 1 つだけです。所有権を解放するには、ReleaseMutex 関数を使います。 1 つのミューテックスを所有しているスレッドは、待機関数を繰り返し呼び出す場合に、自らの実行をブロックすることなく、そのミューテックスを指定できます。通常、同じミューテックスを繰り返し待機することはないはずですが、このメカニズムは、スレッドが既に自ら所有しているミューテックスを待機しようとしてデッドロックに陥ることを防止します。ただし、このスレッドが自らの所有権を解放するには、ミューテックスが待機の条件を満たすたびに、このスレッドから ReleaseMutex 関数を呼び出さなければなりません。 複数のプロセスが CreateMutex 関数を使って、同じ名前のミューテックスを作成することもできます。最初に実行されたプロセスはそのミューテックスを実際に作成しますが、2 番目以降のプロセスは既存のミューテックスのハンドルを開くだけです。この結果、複数のプロセスが同じミューテックスに対するハンドルを取得するので、ミューテックスを作成する特定のプロセスを決定して、そのプロセスを必ず最初に起動することを保証する必要がなくなります。この手法を使う場合、bInitialOwner パラメータで FALSE を指定してください。さもないと、どのスレッドが最初の所有権を取得したのか判断しにくくなることがあります。 複数のプロセスに同じミューテックスオブジェクトのハンドルを割り当てて、プロセス間同期の目的でそのオブジェクトを使うことができます。次のようなオブジェクト共有メカニズムを利用できます。 •CreateMutex 関数の lpMutexAttributes パラメータでミューテックスオブジェクトの継承を有効にしておくと、CreateProcess 関数が作成した子プロセスは、ミューテックスオブジェクトのハンドルを継承できます。 •プロセスは、特定のミューテックスオブジェクトのハンドルを指定して DuplicateHandle 関数を呼び出すことにより、ハンドルを複製できます。他のプロセスは、そのハンドルを使うことができます。 •プロセスは、OpenMutex または CreateMutex 関数を呼び出す際に、ミューテックスオブジェクトの名前を指定できます。 ハンドルを閉じるには、CloseHandle 関数を使います。プロセスが終了する際に、システムはそのプロセスが所有していたハンドルを自動的に閉じます。ミューテックスオブジェクトに対して 1 つまたは複数のハンドルが開いている場合、最後のハンドルが閉じた時点で、そのミューテックスオブジェクトは破棄されます。

回答No.1

> とするのは正しくて/*x*/の行を削除して//をとり > hMutexの位置を前に持ってくるのは間違っているのでしょうか? 質問の意図は? そう考える根拠は何ですか?

nubou
質問者

補足

ありがとうございます Mutexは宣言するだけでクリエイトしなくても使えるのかどうかということが分からないのです Mutexが後ろにある場合はMutexをクリエイトする前にMutexを使ってます 要するにMutexは宣言しただけで使えて 必ずしもMutexを使う場合にはMutexをクリエイトするまで待ってMutexを使わなければならないのかということを知りたいのです

関連するQ&A

  • スレッドの終了を知りたい(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; } ----プログラム(該当部分)ここまで----

  • 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);は必要ですか?

  • スレッド内でのマルチスレッドの作成[WINDOWSプログラミング]

    いつもお世話になっております。 現在WINDOWSプログラムでゲームを最中なのですが、スレッド内でスレッドを作成できなくて困っています。 キャラを動かすスレッドで以下の関数を使い、スレッドを作成しようとしたのですが、 CreateThread(NULL, 0, ATK, (LPVOID)&x, 0, &dwID); 以下のようなエラーメッセージが出てしまいます。 'ATK':定義されていない識別子です '関数' : 間接参照のレベルが 'LPTHREAD_START_ROUTINE' と 'int' で異なっています。 'CreateThread' : の型が 3 の仮引数および実引数と異なります。 わかる方いましたらどうがご指導お願いします。 初歩的なミスでしたらすみません。

  • WINAPIのスレッドについて教えてください

    WINAPIのスレッドについて教えてください スレッドを作成して写真をスライドショウー的に表示しようしていますが、 上手くいきません。 typedef struct _dataparam{ HWND hWnd; HDC hSlidDC; int iFileCount; TCHAR szFile[100][MAX_PATH]; HBITMAP hBitmap[100]; }DataParam; という構造体を作成して、各変数に必要な値を代入した後 BIT_SLIDというメッセージが来た場合Threadを作成。 LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) { static DataParam data={0}; case WM_CREATE: data.hWnd=hWnd; ・ ・ case BIT_SLID: slidCheck=TRUE; CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SlidThread, (LPVOID)&data,0,&dwThreadId); return 0; Thread関数内でGetClientRectにより下記のように Windowのサイズを測ろうとしましたが rcには正しいWindowのサイズ格納されていません。 DWORD WINAPI SlidThread(LPVOID vdParam) { DataParam *SlidData; RECT rc={0}; SlidData=(DataParam *)vdParam; GetClientRect(SlidData->hWnd,&rc); ・ ・ ・ hWnd以外のiFileCountやszFile[100][MAX_PATH]の値を調べると 問題なく引き渡しているようなのですが、 rcのleft=0 light=459 top=760 bottom=-2142242063となっていました。 けれどThread関数内で InvalidateRect(SlidData->hWnd,NULL,TRUE); 再描画を行います。 ちなみに下記の自作関数では問題なくWindowサイズを取得しております。 int MySetBitmap(HDC hNormalDC,DataParam *data) { GetClientRect(data->hWnd,&rc); ・ ・ ・ 環境はMicrosoft Visual C++ 2008 Express Editionです それと別件なのですが、デバックでローカルに表示される変数と 表示されない変数がありますがその違いを教えていただければ幸いです。 今回SlidDataは表示されません。 ご教授お願いします。

  • 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); 宜しければご指摘お願い致します。

  • 2重起動を防ぐために

    WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) { WNDCLASS wc; HWND hW; MSG ms; HANDLE hMutex; hMutex=CreateMutex(NULL,TRUE,"UniqueName"); if(!hMutex)return FALSE; if (GetLastError()==ERROR_ALREADY_EXISTS)return FALSE; とすればよいいうサイトがあります。 こうした後、最終的にこのアプリを終了するときMutexを閉じる必要はあるのでしょうか。 アプリの終了で自動的に閉じられるから何もしなくてよいのでしょうか教えてください。

  • _beginthread()の使用について

    元々スレッドの生成を CreateThread(NULL, 0, ThreadFunc, (LPVOID)&param, 0, &dwID); としていたのですが、 生成したスレッドがC言語のライブラリを利用する場合、 CreateThread()ではなく_beginthread()を使うとMSDNに記載されていました。 そこでプログラムを_beginthread()に書き換えたのですが、 『error C2440: '関数' : 'DWORD (__stdcall *)(LPVOID)' から 'void (__cdecl *)(void *)' に変換できません。』 『warning C4024: '_beginthread' : の型が 1 の仮引数および実引数と異なります。』 とのエラーが表示されてしまいます。 アドバイスをよろしくお願いします。 #include <windows.h> #include <process.h> #define APP_NAME TEXT("Sample_MainWindow") typedef struct _ThreadParam {   HWND owner;   POINT point; } ThreadParam; DWORD WINAPI ThreadFunc(LPVOID vdParam) {      ・     (省略)      ・ } LRESULT CALLBACK WindowProc(   HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {   ThreadParam param;   switch(uMsg) {     case WM_LBUTTONDOWN:       param.owner = hWnd;       param.point.x = LOWORD(lParam);       param.point.y = HIWORD(lParam);       _beginthread(ThreadFunc, 0, &param);       return 0;     }   return DefWindowProc(hWnd, uMsg, wParam, lParam); }

  • BHO-2

    http://eternalwindows.jp/browser/mshtml/mshtml01.html の関数を、 http://msdn.microsoft.com/ja-jp/library/bb250489(v=vs.85).aspx のなかに組み込みたいと思っています。 BOOL CHelloWorldBHO::GetDocumentFromIE(IHTMLDocument3 **pp) { HWND hwnd; UINT uMsg; LRESULT lResult; HRESULT hr; EnumChildWindows(FindWindow(TEXT("IEFrame"), NULL), EnumChildProc, (LPARAM)&hwnd); if (hwnd == NULL){ return FALSE; } uMsg = RegisterWindowMessage(TEXT("WM_HTML_GETOBJECT")); if (!SendMessageTimeout(hwnd, uMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, (LPDWORD)&lResult)){ MessageBox(NULL, L"WM_HTML_GETOBJECT", L"BHO", MB_OK); return FALSE; } hr = ObjectFromLresult(lResult, IID_IHTMLDocument3, 0, (void **)pp); if (FAILED(hr)) return FALSE; MessageBox(NULL, L"Hello World! ie-end", L"BHO", MB_OK); return TRUE; } で、 uMsg = RegisterWindowMessage(TEXT("WM_HTML_GETOBJECT")); if (!SendMessageTimeout(hwnd, uMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, (LPDWORD)&lResult)){ MessageBox(NULL, L"WM_HTML_GETOBJECT", L"BHO", MB_OK); return FALSE; } の部分で失敗します。 原因はなんでしょうか・ VS2005 と Win7 を使っています。 MessageBox(NULL, L"WM_HTML_GETOBJECT", L"BHO", MB_OK); はバグの確認のため入れてあります。 アドバイスよろしくお願いします。

  • 2重軌道防止のサイトの説明

    に従って以下のようにしましたが 2重起動を発見してやめるために return false; としていますが return true; としたり booleanをやめて return int(0) とするとどうなるのでしょうか? WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) { WNDCLASS wc; HWND hW,hPW; MSG ms; unsigned pos; HANDLE hMutex; hPW=FindWindow("goo","I am good."); hMutex=CreateMutex(NULL,TRUE,"UniqueName"); if(!hMutex)return FALSE; if (GetLastError()==ERROR_ALREADY_EXISTS) { ShowWindow(hPW,SW_RESTORE); SetForegroundWindow(hPW); return FALSE; } ・・・・・・・・・・・・・・・・・・・・

  • 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; }

専門家に質問してみよう