Отладка RtlUserThreadStart в Process Explorer

У меня есть многопоточное приложение wpf, построенное на 3.5. Когда я смотрю на запущенные потоки через Process Explorer, я вижу 8 потоков с одинаковым начальным адресом, ntdll.dll!RtlUserThreadStart, и все восемь имеют значение ЦП от 3-6+ и имеют высокую дельту циклов. Я не могу понять, что делают эти потоки. Это всегда одни и те же темы. Он никогда не меняется в пределах одного и того же экземпляра приложения. Когда я одновременно отлаживаю свое приложение и приостанавливаю отладчик, все эти потоки показывают одну строку для стека либо System.Threading.ConcurrencyScheduler.Scheduler.WaitForWork(), либо System.Threading.Monitor.Wait().

Я включил файлы символов для 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

or:

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 ядрами. Когда мы запускаем одно и то же приложение на двухпроцессорном процессоре с 4 ядрами, мы видим, что количество потоков увеличивается с 8 до 16.


person Ben    schedule 27.06.2012    source источник
comment
Вам понадобятся лучшие символы отладки, если вы хотите отладить это именно так. Любой символ, который появляется со смещением более 0x100, в основном является мусором и не говорит вам, что происходит на самом деле. Сейчас вы можете видеть только экспортированные функции. Включите сервер символов Microsoft, чтобы улучшить pdbs.   -  person Hans Passant    schedule 28.06.2012
comment
Я добавил стек, предоставляемый Visual Studio при включении сервера символов. Я не знаю, как расширить стек, предоставленный в Process Explorer.   -  person Ben    schedule 28.06.2012
comment
Кстати: Process Explorer, похоже, показывает RtlUserThreadStart, если у него нет полного разрешения на просмотр изображения. Например, я заметил это, когда запущен установщик MSI. Когда вы используете параметр «Файл» -> «Показать всю информацию о процессе», он разрешает стек для более глубоких элементов. (Вы также заметили, что кнопка трассировки стека выводит ошибку без повышенных привилегий.   -  person eckes    schedule 21.01.2015


Ответы (2)


Ваш вопрос, к сожалению, недостаточно задокументирован, но разумно предположить, что вы, похоже, используете библиотеку PPL. Что поддерживает пул потоков для выполнения параллельных заданий. Вы, несомненно, наблюдаете большое количество циклов ЦП, потому что эти потоки действительно выполняют работу, которую вы от них просили.

Как это обычно бывает с пулами потоков, PPL сохраняет эти потоки для выполнения следующего задания, поэтому вы видите, что они ожидают ожидания в WaitForWork(). Собственные трассировки стека являются ненужными из-за отсутствия символов отладки. В противном случае RtlUserThreadStart — это функция Windows, которую вы всегда будете видеть в неуправляемой трассировке стека, именно так запускается поток.

Это все совершенно нормально. Единственная другая информация, заслуживающая внимания, это этот ответ опубликован сотрудником Microsoft:

Среда выполнения с параллелизмом кэширует потоки для последующего повторного использования. Они освобождаются только после завершения работы всех планировщиков среды выполнения с параллелизмом. (Как правило, в процессе используется только один планировщик по умолчанию). Планировщик выключается, когда все внешние потоки, которые поставили в очередь работу с ним, завершились. Таким образом, если основной поток запланировал работу (скажем, вызвав parallel_for из main()), то планировщик по умолчанию будет удален только при завершении процесса.

Существует верхний предел количества кэшируемых потоков. Это примерно в 4 раза больше количества ядер на машине (хотя есть и другие факторы, влияющие на порог, например параметр размера стека в политиках планировщика).

person Hans Passant    schedule 28.06.2012
comment
Я понимаю концепцию сохранения этих потоков для последующего использования. Чего я не понимаю или не знаю, как отлаживать, так это почему каждый из них потребляет так много процессора, когда они просто ждут работы? Я вижу, что каждый из них потребляет 3-6+% процессора. - person Ben; 28.06.2012
comment
Потому что эти потоки действительно работают? Вы написали многопоточное приложение wpf, оно должно работать. Process Explorer не поможет поймать их иногда за работой. Когда он делает снимок, он использует одно ядро ​​вашего процессора, что значительно снижает вероятность того, что один из этих рабочих процессов будет выполняться. Добавьте инструментальный код или используйте анализатор параллелизма, чтобы получить более полное представление. - person Hans Passant; 28.06.2012

Я выяснил, что вызывает высокую загрузку ЦП в этих потоках, которые находятся в состоянии ожидания. Хотя я пока не знаю, почему это происходит. Когда наше приложение было приложением .NET 3.5, кто-то здесь нашел и использовал доступную сборку потоков, которую кто-то портировал обратно, или что-то из .NET 4.0/4.5 для использования с 3.5. Это, по-видимому, имеет дефект в вызове Parallel.ForEach или что-то в этом роде. Когда я вызываю этот вызов, я заканчиваю тем, что эти потоки сидят в ожидании после цикла, потребляя ЦП. Мы подтвердили Microsoft, что эти потоки на самом деле просто ждали. Теперь у нас 4.0, и я переключился на библиотеку задач, доступную в 4.0, и проблема исчезла. Я попытаюсь выполнить отладку в библиотеке, когда у меня будет возможность посмотреть, смогу ли я указать конкретную причину, по которой это происходило.

person Ben    schedule 18.09.2013