C# WPF Потоки пустой программы

125
11 октября 2019, 16:20

Process Explorer показывает 12 Threads в пустой release WPF программе. Почему так много и как их понимать? Где-то читал что WPF создает 2 потока один для программы и один для UI.

Answer 1

Информацию о некоторых служебных потоках CLR можно прочитать здесь. Воспользуемся Debugging Tools for Windows, чтобы проверить это на практике.

Запускаем исследуемое приложение (без отладки), запускаем WinDbg, выбираем File -> Attach to process, выбираем в списке наше приложение. Приостанавливаем выполнение с помощью Ctrl+Break. Теперь мы можем получить стеки вызовов всех потоков с помощью команды ~* k:

0:012> ~* k
   0  Id: 2b20.1f0c Suspend: 1 Teb: 01086000 Unfrozen
 # ChildEBP RetAddr  
00 012ff24c 73f6a850 win32u!NtUserGetMessage+0xc
*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\WindowsBase\03c76d7ce2fb4e82a604311437d4c78e\WindowsBase.ni.dll
*** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v4.0.30319_32\WindowsBase\03c76d7ce2fb4e82a604311437d4c78e\WindowsBase.ni.dll
01 012ff288 544d9590 USER32!GetMessageW+0x30
WARNING: Stack unwind information not available. Following frames may be wrong.
02 012ff2d0 544ae046 WindowsBase_ni+0xe9590
03 012ff2ec 544aaa80 WindowsBase_ni+0xbe046
04 012ff328 544a8541 WindowsBase_ni+0xbaa80
05 012ff380 544a816e WindowsBase_ni+0xb8541
*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\Presentatio5ae0f00f#\1ffa8aee628840413da5d86076124375\PresentationFramework.ni.dll
*** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v4.0.30319_32\Presentatio5ae0f00f#\1ffa8aee628840413da5d86076124375\PresentationFramework.ni.dll
06 012ff38c 51c04eca WindowsBase_ni+0xb816e
07 012ff39c 51c04d60 PresentationFramework_ni+0x2c4eca
08 012ff3bc 51c04b07 PresentationFramework_ni+0x2c4d60
09 012ff3cc 05918004 PresentationFramework_ni+0x2c4b07
0a 012ff3d8 7322ebb6 0x5918004
0b 012ff3e4 73231e10 clr!CallDescrWorkerInternal+0x34
0c 012ff438 73237994 clr!CallDescrWorkerWithHandler+0x6b
0d 012ff4a8 733a5026 clr!MethodDescCallSite::CallTargetWorker+0x16a
0e 012ff5d4 733a5707 clr!RunMain+0x1ad
0f 012ff848 733a55ed clr!Assembly::ExecuteMainMethod+0x124
10 012ffd40 733a58d3 clr!SystemDomain::ExecuteMainMethod+0x631
11 012ffd98 733a5819 clr!ExecuteEXE+0x4c
12 012ffdd8 73375a0c clr!_CorExeMainInternal+0xdc
13 012ffe14 739fd93b clr!_CorExeMain+0x4d
14 012ffe50 73a7e8b9 mscoreei!_CorExeMain+0x10e
15 012ffe64 73a84e18 MSCOREE!ShellShim__CorExeMain+0xa9
16 012ffe6c 73d88484 MSCOREE!_CorExeMain_Exported+0x8
17 012ffe80 774141c8 KERNEL32!BaseThreadInitThunk+0x24
18 012ffec8 77414198 ntdll!__RtlUserThreadStart+0x2f
19 012ffed8 00000000 ntdll!_RtlUserThreadStart+0x1b
   1  Id: 2b20.3868 Suspend: 1 Teb: 01089000 Unfrozen
 # ChildEBP RetAddr  
00 0150f86c 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 0150fa28 73d88484 ntdll!TppWorkerThread+0x296
02 0150fa3c 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 0150fa84 77414198 ntdll!__RtlUserThreadStart+0x2f
04 0150fa94 00000000 ntdll!_RtlUserThreadStart+0x1b
   2  Id: 2b20.9dc Suspend: 1 Teb: 0108c000 Unfrozen
 # ChildEBP RetAddr  
00 0172fcfc 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 0172feb8 73d88484 ntdll!TppWorkerThread+0x296
02 0172fecc 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 0172ff14 77414198 ntdll!__RtlUserThreadStart+0x2f
04 0172ff24 00000000 ntdll!_RtlUserThreadStart+0x1b
   3  Id: 2b20.3394 Suspend: 1 Teb: 0108f000 Unfrozen
 # ChildEBP RetAddr  
00 018ffb14 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 018ffcd0 73d88484 ntdll!TppWorkerThread+0x296
02 018ffce4 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 018ffd2c 77414198 ntdll!__RtlUserThreadStart+0x2f
04 018ffd3c 00000000 ntdll!_RtlUserThreadStart+0x1b
   4  Id: 2b20.1610 Suspend: 1 Teb: 01092000 Unfrozen
 # ChildEBP RetAddr  
00 01aef830 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 01aef9ec 73d88484 ntdll!TppWorkerThread+0x296
02 01aefa00 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 01aefa48 77414198 ntdll!__RtlUserThreadStart+0x2f
04 01aefa58 00000000 ntdll!_RtlUserThreadStart+0x1b
   5  Id: 2b20.3bac Suspend: 1 Teb: 01095000 Unfrozen
 # ChildEBP RetAddr  
00 0338fc94 75fa5a13 ntdll!NtWaitForMultipleObjects+0xc
01 0338fe28 73374a4b KERNELBASE!WaitForMultipleObjectsEx+0x133
02 0338fe94 733749a0 clr!DebuggerRCThread::MainLoop+0x99
03 0338fec4 733748cd clr!DebuggerRCThread::ThreadProc+0xd0
04 0338fef4 73d88484 clr!DebuggerRCThread::ThreadProcStatic+0xc4
05 0338ff08 774141c8 KERNEL32!BaseThreadInitThunk+0x24
06 0338ff50 77414198 ntdll!__RtlUserThreadStart+0x2f
07 0338ff60 00000000 ntdll!_RtlUserThreadStart+0x1b
   6  Id: 2b20.334c Suspend: 1 Teb: 01098000 Unfrozen
 # ChildEBP RetAddr  
00 055af738 75fa5a13 ntdll!NtWaitForMultipleObjects+0xc
01 055af8cc 733c16eb KERNELBASE!WaitForMultipleObjectsEx+0x133
02 055af8fc 733b039e clr!FinalizerThread::WaitForFinalizerEvent+0x8a
03 055af92c 7323a029 clr!FinalizerThread::FinalizerThreadWorker+0x5f
04 055af940 7323a093 clr!ManagedThreadBase_DispatchInner+0x71
05 055af9e4 7323a160 clr!ManagedThreadBase_DispatchMiddle+0x7e
06 055afa40 733a4e38 clr!ManagedThreadBase_DispatchOuter+0x5b
07 055afa68 733a4ea5 clr!ManagedThreadBase::FinalizerBase+0x33
08 055afaa4 732aed61 clr!FinalizerThread::FinalizerThreadStart+0xd9
09 055afb48 73d88484 clr!Thread::intermediateThreadProc+0x55
0a 055afb5c 774141c8 KERNEL32!BaseThreadInitThunk+0x24
0b 055afba4 77414198 ntdll!__RtlUserThreadStart+0x2f
0c 055afbb4 00000000 ntdll!_RtlUserThreadStart+0x1b
   7  Id: 2b20.377c Suspend: 1 Teb: 0109b000 Unfrozen
 # ChildEBP RetAddr  
00 05cbfa10 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 05cbfbcc 73d88484 ntdll!TppWorkerThread+0x296
02 05cbfbe0 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 05cbfc28 77414198 ntdll!__RtlUserThreadStart+0x2f
04 05cbfc38 00000000 ntdll!_RtlUserThreadStart+0x1b
   8  Id: 2b20.3588 Suspend: 1 Teb: 0109e000 Unfrozen
 # ChildEBP RetAddr  
00 05dffab8 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 05dffc74 73d88484 ntdll!TppWorkerThread+0x296
02 05dffc88 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 05dffcd0 77414198 ntdll!__RtlUserThreadStart+0x2f
04 05dffce0 00000000 ntdll!_RtlUserThreadStart+0x1b
   9  Id: 2b20.35ec Suspend: 1 Teb: 010a1000 Unfrozen
 # ChildEBP RetAddr  
00 05f3f54c 75fa5a13 ntdll!NtWaitForMultipleObjects+0xc
01 05f3f6e0 76f8d24e KERNELBASE!WaitForMultipleObjectsEx+0x133
02 05f3f81c 76fee2ae combase!WaitCoalesced+0xb5 [onecore\com\published\comutils\coalescedwait.cxx @ 72] 
03 05f3f84c 76f8ae34 combase!CROIDTable::WorkerThreadLoop+0x4e [onecore\com\combase\dcomrem\refcache.cxx @ 1650] 
04 05f3f878 76f8802f combase!CRpcThread::WorkerLoop+0x11f [onecore\com\combase\dcomrem\threads.cxx @ 269] 
05 05f3f888 73d88484 combase!CRpcThreadCache::RpcWorkerThreadEntry+0x1f [onecore\com\combase\dcomrem\threads.cxx @ 76] 
06 05f3f89c 774141c8 KERNEL32!BaseThreadInitThunk+0x24
07 05f3f8e4 77414198 ntdll!__RtlUserThreadStart+0x2f
08 05f3f8f4 00000000 ntdll!_RtlUserThreadStart+0x1b
  10  Id: 2b20.20e8 Suspend: 1 Teb: 010a4000 Unfrozen
 # ChildEBP RetAddr  
00 061ffab4 75f94699 ntdll!NtWaitForSingleObject+0xc
01 061ffb28 75f945f2 KERNELBASE!WaitForSingleObjectEx+0x99
02 061ffb3c 515f10b7 KERNELBASE!WaitForSingleObject+0x12
03 061ffb68 515f33b8 wpfgfx_v0400!CPartitionManager::GetWork+0x165
04 061ffb80 5164088f wpfgfx_v0400!CPartitionThread::Run+0x18
05 061ffba8 73d88484 wpfgfx_v0400!CPartitionThread::ThreadMain+0x2f
06 061ffbbc 774141c8 KERNEL32!BaseThreadInitThunk+0x24
07 061ffc04 77414198 ntdll!__RtlUserThreadStart+0x2f
08 061ffc14 00000000 ntdll!_RtlUserThreadStart+0x1b
  11  Id: 2b20.3268 Suspend: 1 Teb: 010a7000 Unfrozen
 # ChildEBP RetAddr  
00 092df710 774016d6 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 092df8cc 73d88484 ntdll!TppWorkerThread+0x296
02 092df8e0 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 092df928 77414198 ntdll!__RtlUserThreadStart+0x2f
04 092df938 00000000 ntdll!_RtlUserThreadStart+0x1b
# 12  Id: 2b20.4e8 Suspend: 1 Teb: 010ad000 Unfrozen
 # ChildEBP RetAddr  
00 0f91fd58 77454369 ntdll!DbgBreakPoint
01 0f91fd88 73d88484 ntdll!DbgUiRemoteBreakin+0x39
02 0f91fd9c 774141c8 KERNEL32!BaseThreadInitThunk+0x24
03 0f91fde4 77414198 ntdll!__RtlUserThreadStart+0x2f
04 0f91fdf4 00000000 ntdll!_RtlUserThreadStart+0x1b

Разбираем результат.

Поток 0. По наличию в стеке USER32!GetMessageW, легко понять, что это поток с циклом обработки сообщений (именно на нем запускается большая часть вашего кода, например, обработчики событий и делегаты DispatcherTimer).

Потоки 1, 2, 3, 4, 7, 8, 11. По наличию в стеке ntdll!TppWorkerThread видно, что это потоки из Thread Pool (не пула CLR, а нативного пула Windows). Хороший вопрос, почему 7 потоков Thread Pool автоматически создаются в любом приложении, даже когда мы этого не заказывали (не только в WPF, но и в абсолютно пустом консольном приложении на С++!). Разгадка в том, что в Windows 10 Thread Pool используется для распараллеливания загрузки DLL, с целью ускорения запуска процессов на машинах с несколькими процессорными ядрами.

Поток 5. CLR Debugger Thread - служебный поток, обеспечивающий работу отладчиков управляемого кода.

Поток 6. CLR Finalizer Thread - служебный поток, на котором GC запускает финализаторы.

Поток 9. Стек вызовов мало что дает, но методом исключения, получается это GC Thread. Отсутствие в стеке каких-либо функций CLR, вероятно, объясняется тем, что сборщик мусора еще не был инициализирован на тот момент.

Поток 10. wpfgfx_v0400 - это неуправляемая библиотека, которую WPF использует для рендеринга графики. Так как WPF использует DirectX, для рендеринга нужен отдельный поток, чтобы делать это максимально быстро независимо от загруженности очереди сообщений.

Поток 12. Символ ntdll!DbgUiRemoteBreakin говорит о том, что это поток, порожденный самим отладчиком (реализация отладки в Windows требует инжектирования в отлаживаемый процесс специального потока). Иными словами, этот поток не имеет отношения к приложению.

Всего 13 потоков, из них один привнесен отладчиком - итого 12 потоков собственно приложения. Вроде все удалось опознать. Как видно, непосредственное отношение к WPF действительно имеют только два потока (0 и 10).

READ ALSO
Хэширование строк C#

Хэширование строк C#

Через какиеNET библиотеки возможно хеширование строк в C#

95
Преобразование местного времени в UTC

Преобразование местного времени в UTC

Почему эта строка даёт мне локальное время с компьютера?

106
Парсинг документа .doc

Парсинг документа .doc

Основываясь на справочнике по структуре документа с разрешениемdoc решил написать программу для получения текстовой части этого документа

116