
Windows2000又はXPで動作させるプログラムを作成していますが、スレッド(AfxBeginThread()で作成した処理)からは待機関数(WaitForMultipleObjects等)は正常に動作しますが、画面のボタン等のクリックイベントからは正常に動作しませんが、これは何故でしょうか?HELPで「このハンドルは、SYNCHRONIZE アクセスを持っていなければなりません」と出ていましたが、何か方法があるのでしょうか?
ちなみに言語はVC++6.0です。
No.2ベストアンサー
- 回答日時:
>実は下記のようなスレッドを使用しないで使いたかったのですが
ボタン2のイベントハンドラに入ると、ボタン2のイベントハンドラを抜けるか、コンテキストスイッチが発生しない限り、他のイベントハンドラに制御が渡される事はありません。
そして、WaitForSingleObjectがINFINITEで待つ間、該当のプロセスは停止しているので、ボタン1をクリックしてもボタン1のイベントハンドラが実行される事はありません。
つまり、ボタン2のイベントハンドラ内でボタン1を押されるのを待っても、ボタン1のイベントハンドラは実行されない為、オブジェクトがシグナル状態になる事はありません。
chie65535さん的確な回答ありがとうございました。
なんとなく薄々感じてはいたのですが、ボタンクリック等の処理からでは出来ないのですね。実はあるユニットと通信をしているので、完了待ちの処理でWaitForSingleObject等が使えればCPUも軽減出来ると思ったのですが、今まで通り待ちのループでPeekMessageでメッセージをディスパッチする方法で行きます。
while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
No.4
- 回答日時:
>今まで通り待ちのループでPeekMessageでメッセージをディスパッチする方法で行きます。
>while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0)
>{
>TranslateMessage(&Msg);
>DispatchMessage(&Msg);
>}
上記の方法は、Windowsプログラミングでは推奨されません。と言うか、やってはいけません。
本来、メッセージループはメイン関数の1ヶ所のみで行うべきです。
しかも、自分でメッセージループを書かないフォームアプリケーションの場合、ライブラリで用意されたメッセージループは
while (GetMessage(&msg,NULL,0,0))
{
if (hFindWnd && IsDialogMessage(hFindWnd,&msg)) continue;
if (hHLPWnd)
{
if (PropSheet_GetCurrentPageHwnd(hHLPWnd) == NULL)
{
DestroyWindow(hHLPWnd);
hHLPWnd = NULL;
} else if (PropSheet_IsDialogMessage(hHLPWnd,&msg))continue;
}
if (!TranslateAccelerator(hMainWnd,hAccel,&msg) && !TranslateMDISysAccel(hClientWnd,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
のように、非常に複雑です(実物はもっともっと複雑です)
質問者さんのように「取りあえずのメッセージのディスパッチ」では、ダイアログ、MDI、HELPに対応できません。
もし、そのアプリの中でダイアログ、MDI、HELPを用いた瞬間、プログラムは「応答なし」になります。
>実はあるユニットと通信をしているので、完了待ちの処理で
はっきり申し上げると「完了待ちを行う事自体が間違いであり、Windowsアプリケーションでは『待ちループ』を作ってはいけない」のです。
質問者さんが書くべき処理は、以下のようになります。
・メッセージループではなく、WindowProcコールバック関数に、通信終了メッセージを受け付けた場合の処理を追加する。そして、そこで「『通信中』ダイアログを、IDOKで閉じる」と言う処理を行う。もちろん、『通信中』ダイアログが開かれていない場合は、このメッセージは「処理済み」として扱う。
・ボタン押下イベントで、スレッドに通信開始を指示する。
・スレッドに通信開始を指示した後に、「通信中」の表示を行うダイアログをモーダルで表示する(メインプログラムはここで停止し、先に進まない。モーダルなダイアログがあるのでフォーカスを受け取る事もできなくなる)
・「通信中」ダイアログには「通信中断」のボタンだけがあり、これを押すとメインプログラムのボタン押下イベント処理の所に制御が戻る(呼び出し元にはIDCANCELが返る)
ダイアログ表示中、実際のプログラムの制御は、既存の「正規のメッセージループ」にあり、その「正規のメッセージループ」の中からWindowProcコールバック関数が呼ばれ、そこで通信終了のメッセージを判定する事となる。
・ボタン押下イベントで「通信中」の表示を行うダイアログを表示したあと、IDCANCELが返って来たら、スレッドに通信中断を指示するなど、後始末を行う。IDOKが返って来た場合は通信が終了しているので、後始末を行う。
・表示した「通信中」ダイアログを解放(Release)して、ボタン押下イベント関数から抜ける。
このようにすると、既存の「正規のメッセージループ」でメッセージを待つ事となり、ダイアログ、MDI、HELPを追加しても「正規のメッセージループが、すべてちゃんと処理してくれる」ので、プログラムが「応答なし」になる事はありません。
繰り返しますが
**************************************
*****プログラムの正規の場所以外で、メッセージループをしてはいけない*****
**************************************
です。
回答ありがとうございます
何故か回答を戴いたメールが遅れて来て、お礼が遅くなり申し訳ありません。
ご意見を参考に一度プログラム構成を見直して見ます。
No.3
- 回答日時:
こんばんは。
タイマー使うか、
http://msdn.microsoft.com/ja-jp/library/49313fdf …
http://msdn.microsoft.com/ja-jp/library/sfs37s7c …
http://msdn.microsoft.com/ja-jp/library/fy1hkbdk …
スレッドにメッセージを送るか、
http://msdn.microsoft.com/ja-jp/library/cc410979 …
で出来るのではないでしょうか。以下はスレッドにメッセージを送る方です。此れでは駄目でしょうか。
//イベントメッセージ
const UINT WM_MYEVENT = WM_USER + 1000;
//スレッド関数
static UINT Proc(LPVOID pData)
{
MSG msg;
CDlg* p = static_cast<CDlg*>(pData);
//エディットコントロールがあるとする
p->SetDlgItemText(IDC_EDIT1, "START");
while(::GetMessage(&msg, NULL, 0, 0))
{
switch(msg.message)
{
case WM_MYEVENT:
//スタティックコントロールに表示
p->SetDlgItemText(IDC_STATIC, "Event occurred");
break;
default:;
}
}
//エディットコントロールがあるとする
p->SetDlgItemText(IDC_EDIT1, "END");
return 0;
}
//待機解除
void CKaiketuDlg::OnButton2()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
if(m_pThread)
{
//イベントメッセージを送る
m_pThread->PostThreadMessage(WM_MYEVENT, 0, 0);
//スレッドを閉じる
m_pThread->PostThreadMessage(WM_QUIT, 0, 0);
m_pThread = NULL;
}
}
//待機開始
void CKaiketuDlg::OnButton1()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
if(m_pThread == NULL)
m_pThread = ::AfxBeginThread(&::Proc, this);
}
machongolaさん回答ありがとうございます。
本来の目的を説明せずに内容だけ質問した為ご心配をして頂きありがとうございました。目的はボタンクリック等の処理から、ある装置と通信を行います。この時装置からの完了(実際の送信と応答の受信はスレッドで処理しています)を待って次のコマンドを送る必要がある為、完了待ちを行う必要があり、現行PeekMessageを使用してメッセージのディスパッチを行っていたのですが、もっとCPUを軽減出来る策が無いかと思い、イベント待ちが行えないか質問をさせて戴いた次第です。次回の新規プログラム作成時の参考にさせて頂きます。
No.1
- 回答日時:
こんばんわ。
(まだ早いかも)WaitForSingleObjectではありますが、テストを作成してみました。
ボタンを押して、CEvent の変数をSetEvent()すると期待通り動作します。スレッドからでなくて、どこからでも動作するようですが。
WaitForMultipleObjectではテストしていません。
あまり使わないので・・・。
BOOL CthrdtstDlg::OnInitDialog()
// TODO: 初期化をここに追加します。
bl_draw = true;
AfxBeginThread(WriteLetters,this);
//AfxBeginThread(Terminate,this);
pEvent = new CEvent(false, false);
UINT WriteLetters (LPVOID pParam)
{
static CthrdtstDlg* pDlg;
pDlg = (CthrdtstDlg*)pParam;
//pDlg->ApplyThreashToMono();
while(pDlg->bl_draw){
pDlg->WriteText();
}
if(!WaitForSingleObject(pDlg->pEvent->m_hObject,INFINITE)){
pDlg->GetDlgItem(IDC_STATIC)->SetWindowTextW(L"Event occurred");
}
return true;
}
void CthrdtstDlg::WriteText(void){
GetDlgItem(IDC_STATIC)->SetWindowTextW(L"Running");
Sleep(1000);
GetDlgItem(IDC_STATIC)->SetWindowTextW(L"Still Running");
Sleep(1000);
}
void CthrdtstDlg::OnBnClickedButton2()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
this->pEvent->SetEvent();
}
wathavyさん早速の回答をありがとうございました。
私の説明が悪かったようです。実は下記のようなスレッドを使用しないで使いたかったのですが、私自身は組み込み系のプログラムが長く、Windowsプログラムはあまり詳しくないので、もしかしたら常識はずれの内容だったのかもしれません。
実はButton2で待機待ちを行い、Button1でButton2の処理の待ち解除が行えないのかなと思って質問をしましたが、この方法は無理なような気がして来ました。どうもありまとうございました。
void CTestDlg::OnButton1()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
this->m_pEvent->SetEvent();
}
void CTestDlg::OnButton2()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
if(!WaitForSingleObject(m_pEvent->m_hObject,INFINITE))
{
GetDlgItem(IDC_STATIC)->SetWindowTextW(L"Event occurred");
}
AfxMessageBox("END");
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Windows 10 explorerをedgeで開く方法 2 2022/06/05 14:59
- PHP htmlspecialcharsが機能していないです。 バグですか? 1 2022/04/05 01:22
- その他(プログラミング・Web制作) プログラムの勉強のおすすめは 7 2022/12/09 20:09
- ドライブ・ストレージ Win10を再インストールしたら、HDDの一部に未割り当て領域ができ何の操作もできません。 4 2023/05/19 05:31
- Access(アクセス) アクセス 意図せずサブプロシージャを移動してしまうのを止めたい 1 2022/09/02 09:19
- YouTube Youtubeのホーム画面がおかしいんです・・・ 7 2023/08/13 22:46
- MySQL 「utf8mb4_general_ci」はMAMPでは何に当たりますか? 1 2022/06/02 07:45
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
- その他(プログラミング・Web制作) pythonで、tkinterとpillowの組み合わせ 2 2022/08/16 17:42
- PHP ここでの ②if($su_d<>"")の比較演算子 を使う理由は 1 2022/03/26 02:33
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
今、見られている記事はコレ!
-
弁護士が語る「合法と違法を分けるオンラインカジノのシンプルな線引き」
「お金を賭けたら違法です」ーーこう答えたのは富士見坂法律事務所の井上義之弁護士。オンラインカジノが違法となるかどうかの基準は、このように非常にシンプルである。しかし2025年にはいって、違法賭博事件が相次...
-
釣りと密漁の違いは?知らなかったでは済まされない?事前にできることは?
知らなかったでは済まされないのが法律の世界であるが、全てを知ってから何かをするには少々手間がかかるし、最悪始めることすらできずに終わってしまうこともあり得る。教えてgooでも「釣りと密漁の境目はどこです...
-
カスハラとクレームの違いは?カスハラの法的責任は?企業がとるべき対応は?
東京都が、客からの迷惑行為などを称した「カスタマーハラスメント」、いわゆる「カスハラ」の防止を目的とした条例を、全国で初めて成立させた。条例に罰則はなく、2025年4月1日から施行される。 この動きは自治体...
-
なぜ批判コメントをするの?その心理と向き合い方をカウンセラーにきいた!
今や生活に必要不可欠となったインターネット。手軽に情報を得られるだけでなく、ネットを介したコミュニケーションも一般的となった。それと同時に顕在化しているのが、他者に対する辛らつな意見だ。ネットニュース...
-
大麻の使用罪がなかった理由や法改正での変更点、他国との違いを弁護士が解説
ドイツで2024年4月に大麻が合法化され、その2ヶ月後にサッカーEURO2024が行われた。その際、ドイツ警察は大会運営における治安維持の一つの方針として「アルコールを飲んでいるグループと、大麻を吸っているグループ...
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
gprofとスレッドについて
-
スレッドの監視方法について
-
C# スレッドから親ウィンドウへ...
-
WaitForMultipleObjectのイベン...
-
別スレッドからメインダイアロ...
-
ユーザーインターフェイスの一...
-
VC++スレッドの正しい終了のさ...
-
スレッドがサスペンドされてい...
-
VB2005 シリアル通信のClose処理
-
WaitForSingleObjectの使い方に...
-
スレッドの安全な終了のさせ方
-
マルチスレッドプログラム
-
待機関数(WaitForMultipleObjec...
-
pThreadのメインでなぜsleep?
-
メモリアクセスの競合について
-
sleep関数とは?
-
スレッドの終了の仕方
-
Macターミナルで実行中のプログ...
-
C# シリアル通信でデータ受信...
-
家電製品の電力周波数を変える機械
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
スレッドの監視方法について
-
VC++スレッドの正しい終了のさ...
-
スレッドにて同一メモリの書き...
-
スレッドの終了の仕方
-
VB2005 シリアル通信のClose処理
-
WaitForSingleObjectの使い方に...
-
別スレッドのデータを受信できない
-
同一スレッドで、ロックをかけ...
-
CWnd::OnTimerのスレッドの取得
-
スレッドの安全な終了のさせ方
-
メインダイアログが最背面に表...
-
スレッド一覧の取得
-
Windows上で、シグナル(SIGTERM...
-
C言語で一定時間待機後、再実行
-
C#でスレッド実行中のイベント...
-
複数スレッドを動作させるのに...
-
.netアプリへのSendMessageでフ...
-
DirectX LPDIRECT3DDEVICE9のマ...
-
スレッド内でコントロールやWin...
-
DirectX 11のConsntanBuffer
おすすめ情報