MS_STA - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

STA

概要

  • STA : Single-Threaded Apartment

  • マルチスレッド・クライアントにスレッドセーフなアクセスを提供する仕組み。

詳細

STAのアパートメント

  • 1スレッドだけ所属できるアパートメント

  • アパートメント属性はスレッドに対して設定される。

STAのオブジェクト

  • 単一のスレッドのアクセスだけを想定しているオブジェクト。

  • 単一のスレッドだけオブジェクトにアクセスすることが保障される。

STAの仕組み

  • スレッド毎にメンバ変数をコピーすることで実現する。

  • メンバ変数は、生成した COM をスレッドの
    Thread Local Storage (TLS) 上にコピーされる。

  • また、他のスレッドから呼び出される場合、
    Windowsメッセージキュー を使用した
    スレッド間マーシャリング(Proxy・Stub)で直列化される。

補足(「メンバ変数をコピーする」の読み解き): この説明は
一部のケースを述べたものなので、全体像を補っておく。

【STA の本質は「1 つのスレッドに固定する」こと】★
   ・STA に属する COM オブジェクトは、
     【生成したスレッドの上でしか実行されない】
   ・他スレッドから呼ぶと
     → Proxy が【メッセージをポストする】
     → 所有スレッドのメッセージ ループが受け取り、
       そのスレッドが実際のメソッドを実行する ★
     → 結果として【直列化される】

   → だから「スレッドセーフに書かなくてよい」
     (常に同じ 1 スレッドしか触らないため)

【原文の「TLS にコピー」について】
   ・これは【スレッドごとに別インスタンスを持つ】
     パターン(ThreadingModel=Apartment で
     各 STA が自分のインスタンスを持つ場合)の説明
   ・COM の ThreadingModel には
       Apartment … STA。スレッドごとに隔離される ★
       Free      … MTA。呼び出し側が同期責任を負う
       Both      … 呼び出し側のアパートメントに従う
       Neutral   … NA(COM+ 由来。切り替えコストが小さい)
     があり、挙動が変わる
【STA の最大の落とし穴:メッセージ ループが必要】★
   ・STA スレッドは
     【メッセージ ポンプを回していないと
       他スレッドからの呼び出しを処理できない】
     → ワーカー スレッドを STA にして
       Application.Run() を回していないと
       呼び出しが【永久にブロックする】★

   ・「Excel を自動化したら固まる」の典型原因
     → UI スレッド(STA)が
       Thread.Sleep / .Result で【止まっている】
     → メッセージが処理されず、COM 呼び出しが返らない
     → 【デッドロック】

補足(.NET から見た STA / MTA): 実務で意識するのは
属性 1 つとスレッド生成時の指定である。

【.NET でのアパートメント指定】★
   ・エントリ ポイント
       [STAThread]  … 【Windows Forms / WPF は必須】★
       [MTAThread]  … コンソール既定(.NET Framework)
   ・自分で作るスレッド
       var t = new Thread(Work);
       t.SetApartmentState(ApartmentState.STA);  // 開始前に
       t.Start();
   ・【スレッド プールのスレッドは常に MTA】★
     → Task.Run の中で STA が要る COM を触ると壊れる
     → 専用の STA スレッドを立てる必要がある

【なぜ Windows Forms / WPF は STAThread が要るのか】
   ・クリップボード、ドラッグ&ドロップ、
     OLE、コモン ダイアログが【COM の STA 前提】だから
     → 外すと「現在のスレッドは
       シングル スレッド アパートメント モードで
       なければなりません」という例外になる ★
【.NET Core 以降】
   ・[STAThread] は【今も有効】(Windows 上)
   ・コンソール アプリの既定は
     .NET Core 以降【MTA】
   ・非 Windows では
     SetApartmentState が
     【PlatformNotSupportedException】を投げる ★

参考

移行メモ(自己リンク): 移行元の参考 1 件目は
[[STA]]と[[MTA]]自ページへのリンクを含んでいたため、
リンクを外してテキストにした。


Tags: 移行, Windows, プログラミング, .NET開発

⚠️ **GitHub.com Fallback** ⚠️