More Related Content
PDF
Reactive extensions入門v0.1
一希 大田
PPTX
async/await のしくみ
信之 岩永
PDF
ドメイン駆動設計のためのオブジェクト指向入門
増田 亨
What's hot (20)
PDF
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
kwatch
PDF
Reactive Programming by UniRx for Asynchronous & Event Processing
Yoshifumi Kawai
Similar to WindowsにおけるUIスレッドの基礎 (16)
PDF
[2000/10] .NET Technical Briefing 2000 / Visual Studio .NET Part I
Tatsuhiko Tanaka
PPTX
An other world awaits you
信之 岩永
WindowsにおけるUIスレッドの基礎3. .NETラボ 勉強会 2021年9月
• ハンドル
– とっちゃん
• 主な活動場所
– わんくま同盟掲示板
– MSDNフォーラム
– わんくま同盟勉強会(休止中)
• お仕事
– ISV
• パッケージソフトの開発
• 良くも悪くも昭和のソフトハウ
ス
– 一応会社員
• Microsoft MVP 歴
– 2005-2008
• Windows – SDK
– 2008-2016
• Visual C++
– 2016-2018
• Visual Studio and Development
Technologies
– 2018-2022
• Developer Technologies
軽く自己紹介
8. .NETラボ 勉強会 2021年9月
• 基本的に詳しい解説はなし
– API、メッセージ、プロシージャとかでてくるけど気にしない
• Windows の GUIアプリの話
– コンソールアプリは少し状況が異なる
– NTサービスはだいぶ状況が異なる
• Native Windows 環境での話
– .NET 環境のUIスレッドも基本的に同じ
– 同じOSの上で直接動くアプリ同士なので内部的には大差ない
おことわり
9. .NETラボ 勉強会 2021年9月
• 現Win32環境が前提
– 現状の動作は正しいものとして扱う
• 動作確認は以下の環境
– Windows 11 21H1
– Surface Book 2
• i7-8650U
• Mem16G/SSD 1T
• Windows は、搭載メモリなどで動作が変わる
– Windows 8 からの挙動
おことわり
13. .NETラボ 勉強会 2021年9月
• メインスレッド
– プロセス作成時に作られるスレッド
– プロセスに一つだけ存在
– メインスレッドが終了するとそのプロセスは破棄される
• サブスレッド
– メインスレッド以外のスレッドの総称
– サブスレッドが動いていていてもプロセスは終了できる
スレッドの種類
14. .NETラボ 勉強会 2021年9月
• シングルスレッド
– メインスレッドのみのプログラム
• システムが内部処理用に作るスレッドを除く
• マルチスレッド
– メインスレッド以外のスレッドがあるプログラム
• CreateThread, std::thread, std::async
• System.Threading.Tasks.Task
スレッドの種類
15. .NETラボ 勉強会 2021年9月
• UIスレッド
– プロセスに0個以上存在
– Windowsのメッセージを処理するスレッド
– アパートメントスレッドと呼ばれることもある
– メインスレッドである必要はない
• ワーカースレッド
– UIスレッド以外のすべてのスレッド
– 非UIスレッドと呼ばれることもある
• もしかして、UIスレッドってなくてもいい?
スレッドの種類
16. .NETラボ 勉強会 2021年9月
• UIスレッドがないと?
– WaitForInputIdle がタイムアウトまで帰ってこない
• リファレンスより
– Waits until the specified process has finished processing its
initial input and is waiting for user input with no input pending,
or until the time-out interval has elapsed.
• 実際のところ…
– プロセスでメッセージを取得(待機)するかタイムアウトまで待
機
• 一般的なアプリではメッセージループに到達するまでに相当
UIスレッドとは-ないとどうなるの?
18. .NETラボ 勉強会 2021年9月
1. コンソールアプリを待機する場合
2. UIスレッドのないアプリを待機する場合
– .NET 5 ランタイムインストーラ
• WiX 3.14 で作成
– DLL Injection 対応でマルチプロセス構造
– サブプロセスの待機が WaitForSingleObject
» UIスレッドではないメインスレッドのみのプロセス
• シンプルなGUIアプリで確認
3. ウィンドウを作ってから1秒待機
4. ウィンドウ作成前に PeekMessage する場合
5. ウィンドウ作成前に MsgWaitForMultipleObjectする場合
WaitForInputIdle の確認
20. .NETラボ 勉強会 2021年9月
• UIスレッド
– 一般にメッセージループを持つスレッドと言われる
– 主にウィンドウメッセージ(HWNDあてメッセージ)を処理
– 他のスレッドやシステムと協調的に動くための根幹を形成する
UIスレッドとは
21. .NETラボ 勉強会 2021年9月
• メッセージループとは?
– メッセージを処理するループの総称
1. メッセージキューからメッセージを取得
2. メッセージを消化
– 宛先ウィンドウのウィンドウプロシージャにメッセージを送る
– スレッド宛てメッセージを処理
3. 繰り返し不要になるまで1,2を繰り返す
– 通常 WM_QUIT を取得するまで
UIスレッドとは-メッセージループとは
22. .NETラボ 勉強会 2021年9月
• 最小のメッセージループ
UIスレッドとは-メッセージループとは
// 最小のメッセージループ
int MinimumMessageLoop()
{
MSG msg;
// メッセージキューからメッセージを取得
while( GetMessage( &msg, nullptr, 0, 0 ) )
{
// (お呪い)入力メッセージを変換
TranslateMessage( &msg );
// msg.hWnd のプロシージャにメッセージを処理させる
DispatchMessage( &msg );
}
return static_cast<int>(msg.wParam);
}
23. .NETラボ 勉強会 2021年9月
• メッセージポンプ
– メッセージの取得と処理部分を切り出した部分処理
– PeekMessageでメッセージを取得して、メッセージを消化
– 空になるまで繰り返すことが多い
• System.Windows.Forms.Application.DoEvents() など
– C++では原則自前実装
• MFC には AfxPumpMessage という1回だけポンプする関数がある
UIスレッドとは
24. .NETラボ 勉強会 2021年9月
• メッセージの主な宛先
– ウィンドウ(HWND)
– スレッド
– メッセージキュー経由のシステム通知
• HWNDはメッセージを介して動作
– メッセージの処理は必ず作成したスレッドで行われる
• 別スレッド(別プロセス)からのメッセージ送信も可能
– スレッド外からのメッセージはメッセージキューを経由
– HWND宛てメッセージはHWNDを作成したスレッドで処理
UIスレッドとは
25. .NETラボ 勉強会 2021年9月
• 同期送信(Send)
– SendMessage 系API
– メッセージ処理を完了するまで帰ってこない
• 同一スレッドからの送信の場合、プロシージャの直接呼出し
• 別スレッドからのSendはメッセージキューを通じて同期化
• 非同期送信(Post)
– PostMessage 系API
– メッセージキューに格納するだけ
– メッセージが処理されたかどうかは呼び出し元では不明
UIスレッドとは-HWNDにメッセージを送るには
26. .NETラボ 勉強会 2021年9月
• スレッド宛てメッセージ送信
– PostThreadMessage API
• 特定の任意のスレッドにPostする
– 処理するプロシージャがない
• メッセージループ内で独自に処理する必要がある
メッセージループをシステムで代替することはでき
ない
UIスレッドとは-スレッドにメッセージを送るには
27. .NETラボ 勉強会 2021年9月
• スレッド内オブジェクト宛てメッセージの受入バッファ
– HWND宛てメッセージ(HWND作成スレッドのキューに届く)
– スレッド内で処理してほしいメッセージ(指定スレッドに届く)
• Send または Post でキューに格納
• 原則すべてのメッセージ送信が格納
– 同一スレッド内の Send のみキューを経由せずに直送
• 優先順位付きキューのようなバッファ
– 種別ごとのキューと状態フラグを持つ複合的なバッファ
UIスレッドとは-メッセージキューとは
28. .NETラボ 勉強会 2021年9月
• メッセージキューの取得優先順位順
1. Sendされたメッセージ(キュー)=QS_SENDMESSAGE
• 同一スレッド内のSendはその場でDispatchされる
2. Postされたメッセージ(キュー)=QS_POSTMESSAGE
3. 入力処理と内部システムイベント=QS_INPUT
4. Sendされたメッセージ(再チェック)= QS_SENDMESSAGE
• 内部処理で生成される場合への対応
5. 無効化領域チェック=QS_PAINT
• 存在すればWM_PAINTを生成
6. タイマー通知チェック=QS_TIMER
• 存在すればWM_TIMERを生成
UIスレッドとは-メッセージキューとは
29. .NETラボ 勉強会 2021年9月
• 優先順位と状態を持つ特別なバッファ
– 同一優先順位なら原則送信順に処理
– GetMessage/PeekMessage は取得条件を指定可能
• 本来の優先順を無視して取得できる
• メッセージを送る側は順番を想定してはならない
– 別スレッドからのSendより同一スレッド内のSend(直送)が優先
• メッセージを受信する側も受信順などを期待できない
– DOWNがきてUPが来ないこともある
– WM_CLOSE が来ないでいきなり WM_DESTROY が来る
UIスレッドとは-メッセージキューとは
32. .NETラボ 勉強会 2021年9月
• メインスレッドの主な役割と特性
– プロセス内で一つだけ
– プロセスの維持
• UIスレッドの主な役割と特性
– メッセージキューからメッセージを取得して適切に処理
– プロセス内に複数作成可能
– UIスレッドはプロセス内に複数作成可能
• バックグラウンド処理でシステム通知を受け取るために分離
– トップレベルウィンドウにしか通知されないメッセージがある
• アパートメントを分離
– 分離するならトップレベルウィンドウレベルが良い
まとめ