#c_sharp #wpf #многопоточность
Process Explorer показывает 12 Threads в пустой release WPF программе. Почему так много и как их понимать? Где-то читал что WPF создает 2 потока один для программы и один для UI.
Ответы
Ответ 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).
Комментариев нет:
Отправить комментарий