Microsoft Windows でのマネージ スレッド処理とアンマネージ スレッド処理
共通言語ランタイムによって作成されたスレッドや、ランタイムの外で作成されてマネージ環境に入ってコードを実行するスレッドを含め、すべてのスレッドは Thread クラスを通じて管理されます。 ランタイムはプロセスにあるスレッドのうち、マネージ実行時環境内でコードを実行したことがあるすべてのスレッドを監視します。 それ以外のスレッドは追跡しません。 スレッドは、ランタイムがマネージ オブジェクトを COM オブジェクトとしてアンマネージ グループに公開するため、COM 相互運用を通してマネージ実行環境に入ることができます。また、COM DllGetClassObject() 関数、およびプラットフォームの起動を通じてもマネージ実行環境に入ることができます。
アンマネージ スレッドが COM 呼び出し可能ラッパー (CCW: COM Callable Wrapper) などを通じてランタイムに入ると、システムはそのスレッドのスレッド ローカル ストアを検証して、内部マネージ Thread オブジェクトを検索します。 見つかった場合、ランタイムはこのスレッドを既に認識しています。 ただし見つからなかった場合、ランタイムは新しい Thread オブジェクトを作成し、作成したオブジェクトをそのスレッドのスレッド ローカル ストアに取り込みます。
マネージ スレッド処理では、Thread.GetHashCode は確立されたマネージ スレッド ID です。 スレッドの値は、それがどのアプリケーション ドメインから取得された値であっても、そのスレッドの有効期間中はほかのスレッドの値と衝突しません。
メモ |
---|
アンマネージ ホストでマネージ スレッドとアンマネージ スレッドとの関係を制御できるため、オペレーティング システムの ThreadId とマネージ スレッドを固定的に関係付ける必要はありません。つまり、高度なホストはファイバー API を使用することによって、多数のマネージ スレッドを同じオペレーティング システムのスレッドにスケジュールしたり、マネージ スレッドを異なるオペレーティング システム スレッド間で移動したりできます。 |
Win32 スレッド処理とマネージ スレッド処理の対応付け
Win32 スレッド処理要素とほぼそれに対応するランタイム スレッド処理要素を次の表に示します。 この対応付けは、同じ機能を示しているわけではありません。 たとえば、TerminateThread は finally 句を実行したり、リソースを解放することはありません。また、TerminateThread は防止できません。 ただし、Thread.Abort は、すべてのロールバック コードを実行し、すべてのリソースをクリアします。また、ResetAbort を使用して拒否できます。 機能について検討する前に、ドキュメントをよく読んでください。
Win32 |
共通言語ランタイム |
---|---|
CreateThread |
Thread と ThreadStart の組み合わせ |
TerminateThread |
|
SuspendThread |
|
ResumeThread |
|
スリープ |
|
スレッド ハンドルの WaitForSingleObject |
|
ExitThread |
同等の項目はありません |
GetCurrentThread |
|
SetThreadPriority |
|
同等の項目はありません |
|
同等の項目はありません |
|
CoInitializeEx (OLE32.DLL) に類似 |
マネージ スレッドと COM アパートメント
マネージ スレッドをマークして、シングルスレッド アパートメントとマルチスレッド アパートメントのどちらをホストするかを示すことができます。 Thread クラスの GetApartmentState、SetApartmentState、TrySetApartmentState の各メソッドは、スレッドのアパートメント状態を返し、割り当てます。 アパートメント状態が設定されていない場合、GetApartmentState は ApartmentState.Unknown を返します。
メモ |
---|
.NET Framework Version 1.0 および 1.1 では、ApartmentState プロパティを使用して、アパートメント状態を取得および設定します。 |
このプロパティは、スレッドが ThreadState.Unstarted 状態にあるときに設定できます。このプロパティは、1 つのスレッドに対して 1 回だけ設定できます。
開始する前にアパートメント状態が設定されていないスレッドは、マルチスレッド アパートメント (MTA) として初期化されます。 ファイナライザー スレッド、および ThreadPool によって制御されるすべてのスレッドは MTA です。
重要 |
---|
アプリケーション スタートアップ コードでは、MTAThreadAttribute または STAThreadAttribute をエントリ ポイント プロシージャに適用する以外に、アパートメント状態を制御する方法はありません。.NET Framework Version 1.0 および 1.1 では、ApartmentState プロパティを最初のコード行として設定できます。これは .NET Framework Version 2.0 では許可されていません。 |
COM に公開されるマネージ オブジェクトは、フリー スレッド マーシャラーを集約した場合と同様に動作します。 つまり、COM に公開されるマネージ オブジェクトは、フリー スレッドな方法ですべての COM アパートメントから呼び出すことができます。 このフリー スレッド動作を示さない唯一のマネージ オブジェクトは、ServicedComponent から派生したオブジェクトです。
マネージ グループでは、コンテキストおよびコンテキスト バインド マネージ インスタンスを使用しない場合、SynchronizationAttribute はサポートされません。 EnterpriseServices を使用する場合、オブジェクトは ServicedComponent から派生している必要があります。ServicedComponent 自体は ContextBoundObject から派生しています。
マネージ コードは、常に COM 規則に従って COM オブジェクトを呼び出します。 ほかのグループでは、マネージ コードは、OLE32 によって示される COM のアパートメント プロキシおよび COM+ 1.0 コンテキスト ラッパーを通じて呼び出します。
ブロッキング問題
スレッドがアンマネージ呼び出しを作成し、アンマネージ コードでスレッドをブロックしたオペレーティング システムにその呼び出しを挿入した場合、ランタイムでは、Thread.Interrupt または Thread.Abort に対してその呼び出しを制御しません。 Thread.Abort を呼び出した場合、スレッドがマネージ コードに再度組み込まれると、ランタイムはそのスレッドを Abort としてマークし、制御します。 アンマネージ ブロックではなくマネージ ブロックの使用をお勧めします。 WaitHandle.WaitOne、WaitHandle.WaitAny、WaitHandle.WaitAll、Monitor.Enter、Monitor.TryEnter、Thread.Join、GC.WaitForPendingFinalizers などは、すべて Thread.Interrupt および Thread.Abort に応答します。 また、スレッドがシングルスレッド アパートメントにある場合、これらのすべてのマネージ ブロッキング操作は、スレッドがブロックされてもメッセージをアパートメントで正しく処理します。