UIスレッド間でCMFCPopupMenu::m_pActivePopupMenuに同時アクセス – 固定ページ 2 – プログラミング – Home

UIスレッド間でCMFCPopupMe...
 
通知
すべてクリア

UIスレッド間でCMFCPopupMenu::m_pActivePopupMenuに同時アクセス

固定ページ 2 / 2

ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

>CTestThread::InitInstance()に以下の2行を追加
>(m_dlgTestはCTestDialog型のメンバ)
>  m_dlgTest.Create(NULL);
>  m_dlgTest.ShowWindow(SW_SHOWNA);

このCreateを、スレッドのコンストラクタで行ってみたらどうなりますか?


返信引用
NOR
 NOR
(@NOR)
ゲスト
結合: 23年前
投稿: 128
Topic starter  

> このCreateを、スレッドのコンストラクタで行ってみたらどうなりますか?

ありがとうございます。
コンストラクタとなぜかASSERTが発生しないようです。

恥ずかしながら原理がわからないのですが、
もしよろしければ、なぜここだと大丈夫なのか教えていただけませんでしょうか。


返信引用
NOR
 NOR
(@NOR)
ゲスト
結合: 23年前
投稿: 128
Topic starter  

>> このCreateを、スレッドのコンストラクタで行ってみたらどうなりますか?
> ありがとうございます。
> コンストラクタとなぜかASSERTが発生しないようです。

テストしている最中に気づいたのですが、
上記の方法で作成したダイアログは、メインスレッド側に属するようで、
CMainFrameにSleep()などを入れてみたところ、
ダイアログも操作できずに固まってしまいました。

これだとスレッド化したことにはならないのではと思われるのですが、
ryoさんの環境で発生しないというのは、この作り方だったということでしょうか?
それとも、CTestThread::InitInstance()内に書いて
UIスレッドからダイアログを表示しても、やはり発生しないのでしょうか?

> 確かに、子スレッドのPreTranslateMessage()で、
> メインフレームのAssertValid()が呼ばれちゃってますね(vv;)。

仲澤@失業者さんの環境では、発生したということですね。
試していただきありがとうございます。

たしかに今回のテストプログラムに限れば
CDialogExではなくCDialogだと大丈夫なようですが、MFCのソース内を見ると
m_pActivePopupMenuを参照しているところが他にもいろいろあり、
そもそもUIスレッドを全く想定していないライブラリなのであれば、
早めに思いとどまって別の方法を探るべきなのかなとも思っています。

特に、フレームウィンドウを持ったUIスレッドはVC6の頃に作成したものがあり、
これを移植できるかということも調査している状況なのです。

なお、自分でもいろいろ調査を続けているのですが、
元となったBCGSoftの更新情報に、以下のような記述がありました。

http://www.bcgsoft.com/bcgcontrolbarpro-versions.htm
CBCGPPopupMenu has a new method: GetSafeActivePopupMenu - returns the active
popup menu in the current UI thread.

これってやはり、BCGSoft自身のライブラリも、
つい最近まではUIスレッドを想定していなかったということなのでしょうか。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

> 恥ずかしながら原理がわからないのですが、
> もしよろしければ、なぜここだと大丈夫なのか教えていただけませんでしょうか。

 今回のNORさんのテストプログラムの親ウインドウはCMainFlameですよね。
 CTestDialogのウインドウはCMainFlameで起動してますよね。
 だとしたら、スレッドもCMainFlameで起動すべきだと思います。
 なぜ、スレッドのコンストラクタでよかったというと、

>CMainFrame::OnCreate()の最後に以下の1行を追加
>  AfxBeginThread(RUNTIME_CLASS(CTestThread));

これをしていたからだと思います。


返信引用
NOR
 NOR
(@NOR)
ゲスト
結合: 23年前
投稿: 128
Topic starter  

> なぜ、スレッドのコンストラクタでよかったというと、
>
>>CMainFrame::OnCreate()の最後に以下の1行を追加
>>  AfxBeginThread(RUNTIME_CLASS(CTestThread));
>
> これをしていたからだと思います。

ですから、スレッドのコンストラクタで作成したCTestDialogは、
メインスレッド側に属してしまいますよね?
それではUIスレッドの機能にはなっていないのです。

なお、マイクロソフトのフォーラムに、
同じようにUIスレッド絡みの問題に対する書き込みを見つけたのですが、
マイクロソフト自身が「今のMFCは複数のUIスレッドを想定していない」
と言ってしまっていました。
http://connect.microsoft.com/VisualStudio/feedback/details/523719/application-deadlock-toolbar-paint-failure-traces-error-cant-draw-toolbar

書き込んだ外人も「退化だろう」みたいに言われているのですが、
マイクロソフトの返答は2010/01/11時点のものなので、
VS2010でも対応されているものではないですよね。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

> ですから、スレッドのコンストラクタで作成したCTestDialogは、
> メインスレッド側に属してしまいますよね?

うーーん、
多分UNIXもそうだと思いますが、(調べてないです(^^;))
 一つのウインドウが複数のウインドウを管理するようになっていないと、
うまくいかないと思います。


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

MSDNによると、UIスレッドをつくるときは
CWinThread::InitInstanceで生成しろとありますが
なぜ?なのか説明が見つけられませんでした。
MSDNのサンプルと同じように、CWinThread::m_pMainWndに入れてみても
特に変化が見られませんでした

>ryoさんの環境で発生しないというのは、この作り方だったということでしょうか?
このつくり方も試していました
この場合、メインのウィンドウににSleepいれたら、止まっちゃいました。

>それとも、CTestThread::InitInstance()内に書いて
>UIスレッドからダイアログを表示しても、やはり発生しないのでしょうか?
CWinThread::Run()を、オーバーライドし、
その中で自作でメッセージループで待つようにすれば、InitInstanceで生成しても
メニュー表示→ダイアログ のエラーが出ないようです。
♯普段、これを多用してるので

CWinThread::PumpMessageをオーバーライドでもいけるかもしません


返信引用
NOR
 NOR
(@NOR)
ゲスト
結合: 23年前
投稿: 128
Topic starter  

返答が遅れてしまい申し訳ありません。
みなさんの方法を試してもうまくいかず、期限などの問題もあったため、
インシデントを1つ使う覚悟でマイクロソフトに問い合わせてみたところ、
上記のフォーラムと同じく、「今のMFCはUIスレッドには対応していない」
「将来のバージョンでは修正を検討する」とのことでした。

なお、同じようにUIスレッドの問題に
ハマってしまった日本人のかたもいらっしゃいました。
http://d.hatena.ne.jp/killswitch5375/20110818/p1

#納品間際に発覚してしまいました。
#昔のMFCのやりかたが通用しなくなっているのは厳しいですね。


返信引用
固定ページ 2 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました