5

3.5 で構築されたマルチスレッドの wpf アプリケーションがあります。Process Explorer で実行中のスレッドを見ると、8 つのスレッドがすべて同じ開始アドレス ntdll.dll!RtlUserThreadStart を持ち、8 つすべての CPU 値が 3 ~ 6+ で、Cycles Delta が高いことがわかります。これらのスレッドが何をしているのかわかりません。いつも同じスレッドです。アプリケーションの同じインスタンス内で変化することはありません。アプリケーションを同時にデバッグし、デバッガーを一時停止すると、これらすべてのスレッドが、System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork() または System.Threading.Monitor.Wait() のいずれかのスタックの 1 行を表示しています。

Visual Studio のシンボル ファイルを有効にすると、これらのスレッドに次のスタックが表示されます。

System.Threading.Monitor.Wait() Normal
mscorlib.dll!System.Threading.Monitor.Wait(object obj, int millisecondsTimeout) + 0x19     bytes
System.Threading.dll!System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork() + 0xd0 bytes  
System.Threading.dll!System.Threading.ConcurrencyScheduler.InternalContext.Dispatch() + 0x74a bytes
System.Threading.dll!System.Threading.ConcurrencyScheduler.ThreadInternalContext.ThreadStartBridge(System.IntPtr dummy) + 0x9f bytes     

プロセス モニター内のスレッドで提供されるスタックを見ると、次のような例が表示されます。

0  ntoskrnl.exe!KeWaitForMultipleObjects+0xc0a
1  ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x732
2  ntoskrnl.exe!KeWaitForSingleObject+0x19f
3  ntoskrnl.exe!_misaligned_access+0xba4
4  ntoskrnl.exe!_misaligned_access+0x1821
5  ntoskrnl.exe!_misaligned_access+0x1a97
6  mscorwks.dll!InitializeFusion+0x990b
7  mscorwks.dll!DeleteShadowCache+0x31ef

また:

0  ntoskrnl.exe!KeWaitForMultipleObjects+0xc0a
1  ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x732
2  ntoskrnl.exe!KeWaitForSingleObject+0x19f
3  ntoskrnl.exe!_misaligned_access+0xba4
4  ntoskrnl.exe!_misaligned_access+0x1821
5  ntoskrnl.exe!KeAcquireSpinLockAtDpcLevel+0x93d
6  ntoskrnl.exe!KeWaitForMultipleObjects+0x26a
7  ntoskrnl.exe!NtWaitForSingleObject+0x41f
8  ntoskrnl.exe!NtWaitForSingleObject+0x78e
9  ntoskrnl.exe!KeSynchronizeExecution+0x3a23
10 ntdll.dll!ZwWaitForMultipleObjects+0xa
11 KERNELBASE.dll!GetCurrentProcess+0x40
12 KERNEL32.dll!WaitForMultipleObjectsEx+0xb3
13 mscorwks.dll!CreateApplicationContext+0x10499
14 mscorwks.dll!CreateApplicationContext+0xbc41
15 mscorwks.dll!StrongNameFreeBuffer+0xc54d
16 mscorwks.dll!StrongNameFreeBuffer+0x2ac48
17 mscorwks.dll!StrongNameTokenFromPublicKey+0x1a5ea
18 mscorwks.dll!CopyPDBs+0x17362
19 mscorwks.dll!CorExitProcess+0x3dc9
20 mscorwks.dll!TranslateSecurityAttributes+0x547f
21 mscorlib.ni.dll+0x8e6bc9

この項目の追加メモとして。私のコンピュータは 4 コアのシングル CPU です。4 コアのデュアル CPU で同じアプリを実行すると、この数のスレッドが 8 から 16 になることがわかります。

4

2 に答える 2

6

あなたの質問はひどく文書化されていませんが、合理的な推測では、PPL ライブラリを使用しているようです。これにより、並列ジョブを実行するためにスレッドのプールが維持されます。これらのスレッドは実際に要求されたジョブを実行しているため、高い CPU サイクル カウントが表示されることは間違いありません。

スレッド プールでよくあることですが、PPL は次のジョブが実行されるまでこれらのスレッドを保持します。そのため、スレッドは WaitForWork() で待機しています。ネイティブ スタック トレースは、デバッグ シンボルがないためジャンクです。それ以外の場合、RtlUserThreadStart は、アンマネージ スタック トレースで常に表示される Windows 関数です。これがスレッドの開始方法です。

これはすべて完全に正常です。注目に値する他の唯一の情報は、Microsoft の従業員によって投稿されたこの回答です。

コンカレンシー ランタイムは、後で再利用するためにスレッドをキャッシュします。これらは、すべての同時実行ランタイム スケジューラがシャットダウンされた場合にのみ解放されます。(通常、プロセスにはデフォルトのスケジューラが 1 つだけ存在します)。スケジューラは、作業をキューに入れていたすべての外部スレッドが終了するとシャットダウンされます。そのため、メイン スレッドが (たとえば main() から parallel_for を呼び出して) 作業をスケジュールした場合、デフォルトのスケジューラはプロセスのシャットダウン時にのみ削除されます。

キャッシュされるスレッドの数には上限があります。これは、マシンのコア数のおよそ 4 倍です (ただし、スケジューラ ポリシーのスタック サイズ オプションなど、しきい値に影響を与える他の要因がいくつかあります)。

于 2012-06-28T12:59:42.247 に答える
3

待機状態にあるこれらのスレッドで CPU 使用率が高くなる原因を突き止めました。なぜそれが起こっているのかはまだわかりません。私たちのアプリケーションが .NET 3.5 アプリケーションだったとき、ここの誰かが、誰かがバックポートした、または .NET 4.0/4.5 から 3.5 で使用するための何かを見つけて利用しました。これは明らかに Parallel.ForEach 呼び出しか何かに欠陥があります。この呼び出しを呼び出すと、これらのスレッドが待機し、ループの後、CPU を消費することになります。これらのスレッドは実際には待機しているだけであることを Microsoft に確認しました。現在は 4.0 で、4.0 で利用可能なタスク ライブラリに切り替えたところ、問題は解消されました。これが発生した特定の理由を提供できるかどうかを確認する機会があれば、ライブラリにデバッグしてみます。

于 2013-09-18T12:32:11.243 に答える