.NETラボ 勉強会 2021年9月
オンラインは反応見れないし
スピーカーさんもその場で拾ってもらえなくて
お互いさみしいので、久しぶりに MISAO を動かしてます。
Twitter で #dotnetlab を付けた
発言を拾って画面に表示してます。
一杯書き込んでくれると嬉しいし楽しいです。
画面に出るまで少しタイムラグがあるのでご了承ください。
始める前に…
.NETラボ 勉強会 2021年9月
Windowsにおける
UIスレッドの基礎
とっちゃん(高萩 俊行)
Microsoft MVP for Developer Technologies
since 2005
https://github.com/Tocchann/dotnetlab202109
.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
軽く自己紹介
.NETラボ 勉強会 2021年9月
Windowsにおける
UIスレッドの基礎
とっちゃん(高萩 俊行)
Microsoft MVP for Developer Technologies
since 2005
https://github.com/Tocchann/dotnetlab202109
.NETラボ 勉強会 2021年9月
• 本日のゴール
• おことわり
• UIスレッドとは
• まとめ
もくじ
.NETラボ 勉強会 2021年9月
本日のゴール
何をもって
UIスレッド
というかを知る
.NETラボ 勉強会 2021年9月
• 本日のゴール
• おことわり
• UIスレッドとは
• まとめ
もくじ
.NETラボ 勉強会 2021年9月
• 基本的に詳しい解説はなし
– API、メッセージ、プロシージャとかでてくるけど気にしない
• Windows の GUIアプリの話
– コンソールアプリは少し状況が異なる
– NTサービスはだいぶ状況が異なる
• Native Windows 環境での話
– .NET 環境のUIスレッドも基本的に同じ
– 同じOSの上で直接動くアプリ同士なので内部的には大差ない
おことわり
.NETラボ 勉強会 2021年9月
• 現Win32環境が前提
– 現状の動作は正しいものとして扱う
• 動作確認は以下の環境
– Windows 11 21H1
– Surface Book 2
• i7-8650U
• Mem16G/SSD 1T
• Windows は、搭載メモリなどで動作が変わる
– Windows 8 からの挙動
おことわり
.NETラボ 勉強会 2021年9月
• 本日のゴール
• おことわり
• UIスレッドとは
• まとめ
もくじ
.NETラボ 勉強会 2021年9月
• スレッドの種類
• UIスレッドとは
UIスレッドとは
.NETラボ 勉強会 2021年9月
• スレッドには2種類の分類がある
– メインスレッドとそれ以外のスレッド
– UIスレッドとそれ以外のスレッド
スレッドの種類
.NETラボ 勉強会 2021年9月
• メインスレッド
– プロセス作成時に作られるスレッド
– プロセスに一つだけ存在
– メインスレッドが終了するとそのプロセスは破棄される
• サブスレッド
– メインスレッド以外のスレッドの総称
– サブスレッドが動いていていてもプロセスは終了できる
スレッドの種類
.NETラボ 勉強会 2021年9月
• シングルスレッド
– メインスレッドのみのプログラム
• システムが内部処理用に作るスレッドを除く
• マルチスレッド
– メインスレッド以外のスレッドがあるプログラム
• CreateThread, std::thread, std::async
• System.Threading.Tasks.Task
スレッドの種類
.NETラボ 勉強会 2021年9月
• UIスレッド
– プロセスに0個以上存在
– Windowsのメッセージを処理するスレッド
– アパートメントスレッドと呼ばれることもある
– メインスレッドである必要はない
• ワーカースレッド
– UIスレッド以外のすべてのスレッド
– 非UIスレッドと呼ばれることもある
• もしかして、UIスレッドってなくてもいい?
スレッドの種類
.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スレッドとは-ないとどうなるの?
.NETラボ 勉強会 2021年9月
DEMO
WaitForInputIdle を確認してみる
.NETラボ 勉強会 2021年9月
1. コンソールアプリを待機する場合
2. UIスレッドのないアプリを待機する場合
– .NET 5 ランタイムインストーラ
• WiX 3.14 で作成
– DLL Injection 対応でマルチプロセス構造
– サブプロセスの待機が WaitForSingleObject
» UIスレッドではないメインスレッドのみのプロセス
• シンプルなGUIアプリで確認
3. ウィンドウを作ってから1秒待機
4. ウィンドウ作成前に PeekMessage する場合
5. ウィンドウ作成前に MsgWaitForMultipleObjectする場合
WaitForInputIdle の確認
.NETラボ 勉強会 2021年9月
• スレッドの種類
• UIスレッドとは
UIスレッドとは
.NETラボ 勉強会 2021年9月
• UIスレッド
– 一般にメッセージループを持つスレッドと言われる
– 主にウィンドウメッセージ(HWNDあてメッセージ)を処理
– 他のスレッドやシステムと協調的に動くための根幹を形成する
UIスレッドとは
.NETラボ 勉強会 2021年9月
• メッセージループとは?
– メッセージを処理するループの総称
1. メッセージキューからメッセージを取得
2. メッセージを消化
– 宛先ウィンドウのウィンドウプロシージャにメッセージを送る
– スレッド宛てメッセージを処理
3. 繰り返し不要になるまで1,2を繰り返す
– 通常 WM_QUIT を取得するまで
UIスレッドとは-メッセージループとは
.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);
}
.NETラボ 勉強会 2021年9月
• メッセージポンプ
– メッセージの取得と処理部分を切り出した部分処理
– PeekMessageでメッセージを取得して、メッセージを消化
– 空になるまで繰り返すことが多い
• System.Windows.Forms.Application.DoEvents() など
– C++では原則自前実装
• MFC には AfxPumpMessage という1回だけポンプする関数がある
UIスレッドとは
.NETラボ 勉強会 2021年9月
• メッセージの主な宛先
– ウィンドウ(HWND)
– スレッド
– メッセージキュー経由のシステム通知
• HWNDはメッセージを介して動作
– メッセージの処理は必ず作成したスレッドで行われる
• 別スレッド(別プロセス)からのメッセージ送信も可能
– スレッド外からのメッセージはメッセージキューを経由
– HWND宛てメッセージはHWNDを作成したスレッドで処理
UIスレッドとは
.NETラボ 勉強会 2021年9月
• 同期送信(Send)
– SendMessage 系API
– メッセージ処理を完了するまで帰ってこない
• 同一スレッドからの送信の場合、プロシージャの直接呼出し
• 別スレッドからのSendはメッセージキューを通じて同期化
• 非同期送信(Post)
– PostMessage 系API
– メッセージキューに格納するだけ
– メッセージが処理されたかどうかは呼び出し元では不明
UIスレッドとは-HWNDにメッセージを送るには
.NETラボ 勉強会 2021年9月
• スレッド宛てメッセージ送信
– PostThreadMessage API
• 特定の任意のスレッドにPostする
– 処理するプロシージャがない
• メッセージループ内で独自に処理する必要がある
メッセージループをシステムで代替することはでき
ない
UIスレッドとは-スレッドにメッセージを送るには
.NETラボ 勉強会 2021年9月
• スレッド内オブジェクト宛てメッセージの受入バッファ
– HWND宛てメッセージ(HWND作成スレッドのキューに届く)
– スレッド内で処理してほしいメッセージ(指定スレッドに届く)
• Send または Post でキューに格納
• 原則すべてのメッセージ送信が格納
– 同一スレッド内の Send のみキューを経由せずに直送
• 優先順位付きキューのようなバッファ
– 種別ごとのキューと状態フラグを持つ複合的なバッファ
UIスレッドとは-メッセージキューとは
.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スレッドとは-メッセージキューとは
.NETラボ 勉強会 2021年9月
• 優先順位と状態を持つ特別なバッファ
– 同一優先順位なら原則送信順に処理
– GetMessage/PeekMessage は取得条件を指定可能
• 本来の優先順を無視して取得できる
• メッセージを送る側は順番を想定してはならない
– 別スレッドからのSendより同一スレッド内のSend(直送)が優先
• メッセージを受信する側も受信順などを期待できない
– DOWNがきてUPが来ないこともある
– WM_CLOSE が来ないでいきなり WM_DESTROY が来る
UIスレッドとは-メッセージキューとは
.NETラボ 勉強会 2021年9月
• 本日のゴール
• おことわり
• UIスレッドとは
• まとめ
もくじ
.NETラボ 勉強会 2021年9月
• スレッドには2種類の分類がある
– メインスレッドとそれ以外のスレッド
– UIスレッドとそれ以外のスレッド
まとめ
.NETラボ 勉強会 2021年9月
• メインスレッドの主な役割と特性
– プロセス内で一つだけ
– プロセスの維持
• UIスレッドの主な役割と特性
– メッセージキューからメッセージを取得して適切に処理
– プロセス内に複数作成可能
– UIスレッドはプロセス内に複数作成可能
• バックグラウンド処理でシステム通知を受け取るために分離
– トップレベルウィンドウにしか通知されないメッセージがある
• アパートメントを分離
– 分離するならトップレベルウィンドウレベルが良い
まとめ
.NETラボ 勉強会 2021年9月
• メインスレッドはUIスレッドとは限らない
– (寿命管理上便利だが)メインスレッドである必要性はない
まとめ
.NETラボ 勉強会 2021年9月
UIスレッドは
メッセージループを持つスレッド
と言われるが、正しくは
メッセージキューからメッセージを
取得する必要のある
スレッドのこと
まとめ
ご清聴ありがとうございました
.NETラボ 勉強会 2021年9月
ご清聴ありがとうございました

WindowsにおけるUIスレッドの基礎

  • 1.
    .NETラボ 勉強会 2021年9月 オンラインは反応見れないし スピーカーさんもその場で拾ってもらえなくて お互いさみしいので、久しぶりにMISAO を動かしてます。 Twitter で #dotnetlab を付けた 発言を拾って画面に表示してます。 一杯書き込んでくれると嬉しいし楽しいです。 画面に出るまで少しタイムラグがあるのでご了承ください。 始める前に…
  • 2.
    .NETラボ 勉強会 2021年9月 Windowsにおける UIスレッドの基礎 とっちゃん(高萩俊行) Microsoft MVP for Developer Technologies since 2005 https://github.com/Tocchann/dotnetlab202109
  • 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 軽く自己紹介
  • 4.
    .NETラボ 勉強会 2021年9月 Windowsにおける UIスレッドの基礎 とっちゃん(高萩俊行) Microsoft MVP for Developer Technologies since 2005 https://github.com/Tocchann/dotnetlab202109
  • 5.
    .NETラボ 勉強会 2021年9月 •本日のゴール • おことわり • UIスレッドとは • まとめ もくじ
  • 6.
  • 7.
    .NETラボ 勉強会 2021年9月 •本日のゴール • おことわり • UIスレッドとは • まとめ もくじ
  • 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 からの挙動 おことわり
  • 10.
    .NETラボ 勉強会 2021年9月 •本日のゴール • おことわり • UIスレッドとは • まとめ もくじ
  • 11.
    .NETラボ 勉強会 2021年9月 •スレッドの種類 • UIスレッドとは UIスレッドとは
  • 12.
    .NETラボ 勉強会 2021年9月 •スレッドには2種類の分類がある – メインスレッドとそれ以外のスレッド – UIスレッドとそれ以外のスレッド スレッドの種類
  • 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スレッドとは-ないとどうなるの?
  • 17.
  • 18.
    .NETラボ 勉強会 2021年9月 1.コンソールアプリを待機する場合 2. UIスレッドのないアプリを待機する場合 – .NET 5 ランタイムインストーラ • WiX 3.14 で作成 – DLL Injection 対応でマルチプロセス構造 – サブプロセスの待機が WaitForSingleObject » UIスレッドではないメインスレッドのみのプロセス • シンプルなGUIアプリで確認 3. ウィンドウを作ってから1秒待機 4. ウィンドウ作成前に PeekMessage する場合 5. ウィンドウ作成前に MsgWaitForMultipleObjectする場合 WaitForInputIdle の確認
  • 19.
    .NETラボ 勉強会 2021年9月 •スレッドの種類 • UIスレッドとは UIスレッドとは
  • 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スレッドとは-メッセージキューとは
  • 30.
    .NETラボ 勉強会 2021年9月 •本日のゴール • おことわり • UIスレッドとは • まとめ もくじ
  • 31.
    .NETラボ 勉強会 2021年9月 •スレッドには2種類の分類がある – メインスレッドとそれ以外のスレッド – UIスレッドとそれ以外のスレッド まとめ
  • 32.
    .NETラボ 勉強会 2021年9月 •メインスレッドの主な役割と特性 – プロセス内で一つだけ – プロセスの維持 • UIスレッドの主な役割と特性 – メッセージキューからメッセージを取得して適切に処理 – プロセス内に複数作成可能 – UIスレッドはプロセス内に複数作成可能 • バックグラウンド処理でシステム通知を受け取るために分離 – トップレベルウィンドウにしか通知されないメッセージがある • アパートメントを分離 – 分離するならトップレベルウィンドウレベルが良い まとめ
  • 33.
    .NETラボ 勉強会 2021年9月 •メインスレッドはUIスレッドとは限らない – (寿命管理上便利だが)メインスレッドである必要性はない まとめ
  • 34.
  • 35.