回答編集履歴
3
間違ってそうな部分を削除
answer
CHANGED
|
@@ -15,11 +15,14 @@
|
|
|
15
15
|
ウィンドウの移動などは全てこの「マウスがクリックされるメッセージ」、「ウィンドウを移動するメッセージ」というように分解されており、それがメッセージループから逐次ディスパッチされてそれぞれの処理が完了します。ということは、メッセージループが停止するだけでこの動作は完全に停止してしまいます。
|
|
16
16
|
「ウィンドウを表示する処理」も例外ではありません。
|
|
17
17
|
|
|
18
|
+
※調べなおしてたら勘違いな気がしてきたので括っておきます
|
|
19
|
+
```
|
|
18
20
|
で、ここからが本題です。
|
|
19
21
|
**サブスレッドからウィンドウを作っても新しくメッセージループは作成されません。**
|
|
20
22
|
サブスレッド内の処理にはメッセージループがありませんよね?
|
|
21
23
|
|
|
22
24
|
別スレッドから画面を作成したとしても、Formの`DoModal`等の処理はメッセージループに依頼を投げた後、メッセージが処理されるのを待つことになります。下位のダイアログなどのクラスはそういった依頼を簡易化する処理だけで成り立っているはずです。このためにサブスレッドからウィンドウを表示しようとしても停止してしまいます。
|
|
25
|
+
```
|
|
23
26
|
|
|
24
27
|
---
|
|
25
28
|
|
|
@@ -38,13 +41,6 @@
|
|
|
38
41
|
|
|
39
42
|
---
|
|
40
43
|
|
|
41
|
-
ただ、正攻法としてはやはりサブスレッドに重たい処理を移行することです。
|
|
42
|
-
どんなに重い処理をメインスレッドでやっていようとその処理を切り出してバックグラウンドプロセスに投げれない理由はそうそうないと思います。
|
|
43
|
-
新しくメッセージループを作って協調動作させるよりよっぽど低コストになるはずです。
|
|
44
|
-
|
|
45
|
-
内部で扱っているフォームのフィールド情報等を全て1個のオブジェクトに詰め、重たい処理の開始から終了までにかかわる部分を一つのメソッドにして非同期化し、そのあとにサブウィンドウを表示するようにしてください。
|
|
46
|
-
|
|
47
|
-
|
|
48
44
|
#追記
|
|
49
45
|
追記勘違いっぽかったので削除しました。
|
|
50
46
|
やったことないことは回答に書いてはダメですね。
|
2
追記を削除
answer
CHANGED
|
@@ -46,42 +46,5 @@
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
#追記
|
|
49
|
-
|
|
49
|
+
追記勘違いっぽかったので削除しました。
|
|
50
|
-
|
|
51
|
-
```C++
|
|
52
|
-
|
|
50
|
+
やったことないことは回答に書いてはダメですね。
|
|
53
|
-
{
|
|
54
|
-
CancellationToken() : Cancel(false) {}
|
|
55
|
-
bool Cancel;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
UINT SubMessageLoop(LPVOID param)
|
|
59
|
-
{
|
|
60
|
-
CancellationToken *token = (*CancellationToken)param;
|
|
61
|
-
MSG msg;
|
|
62
|
-
|
|
63
|
-
while(!token->Cancel && GetMessage(&msg, NULL, 0, 0))
|
|
64
|
-
{
|
|
65
|
-
TranslateMessage(&msg);
|
|
66
|
-
DispatchMessage(&msg);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
```C++
|
|
73
|
-
CancellationToken *token = new CancellationToken()
|
|
74
|
-
CWinThread *sub_message_loop = AfxBeginThread(SubMessageLoop, token);
|
|
75
|
-
AfxBeginThread(TestThreadProc, this);
|
|
76
|
-
|
|
77
|
-
// 重たい処理を行う
|
|
78
|
-
while (...)
|
|
79
|
-
{
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 処理が終わったらサブのメッセージループを止める
|
|
83
|
-
token->Cancel = true;
|
|
84
|
-
WaitForSingleObject(sub_message_loop, INFINITE);
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
ただ、直観的には動作が不安定になりそうな気もするので…`PeekMessage`使う方が自然かもですね。
|
1
追記
answer
CHANGED
|
@@ -42,4 +42,46 @@
|
|
|
42
42
|
どんなに重い処理をメインスレッドでやっていようとその処理を切り出してバックグラウンドプロセスに投げれない理由はそうそうないと思います。
|
|
43
43
|
新しくメッセージループを作って協調動作させるよりよっぽど低コストになるはずです。
|
|
44
44
|
|
|
45
|
-
内部で扱っているフォームのフィールド情報等を全て1個のオブジェクトに詰め、重たい処理の開始から終了までにかかわる部分を一つのメソッドにして非同期化し、そのあとにサブウィンドウを表示するようにしてください。
|
|
45
|
+
内部で扱っているフォームのフィールド情報等を全て1個のオブジェクトに詰め、重たい処理の開始から終了までにかかわる部分を一つのメソッドにして非同期化し、そのあとにサブウィンドウを表示するようにしてください。
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
#追記
|
|
49
|
+
と…思いましたが、ちょっとgooglingしてたら割と自前でピーク皆さんやっているようなので、別のスレッドで以下のようなことをやっていれば十分動くかもしれないですね。
|
|
50
|
+
|
|
51
|
+
```C++
|
|
52
|
+
struct CancellationToken
|
|
53
|
+
{
|
|
54
|
+
CancellationToken() : Cancel(false) {}
|
|
55
|
+
bool Cancel;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
UINT SubMessageLoop(LPVOID param)
|
|
59
|
+
{
|
|
60
|
+
CancellationToken *token = (*CancellationToken)param;
|
|
61
|
+
MSG msg;
|
|
62
|
+
|
|
63
|
+
while(!token->Cancel && GetMessage(&msg, NULL, 0, 0))
|
|
64
|
+
{
|
|
65
|
+
TranslateMessage(&msg);
|
|
66
|
+
DispatchMessage(&msg);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
```C++
|
|
73
|
+
CancellationToken *token = new CancellationToken()
|
|
74
|
+
CWinThread *sub_message_loop = AfxBeginThread(SubMessageLoop, token);
|
|
75
|
+
AfxBeginThread(TestThreadProc, this);
|
|
76
|
+
|
|
77
|
+
// 重たい処理を行う
|
|
78
|
+
while (...)
|
|
79
|
+
{
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 処理が終わったらサブのメッセージループを止める
|
|
83
|
+
token->Cancel = true;
|
|
84
|
+
WaitForSingleObject(sub_message_loop, INFINITE);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
ただ、直観的には動作が不安定になりそうな気もするので…`PeekMessage`使う方が自然かもですね。
|