UnsafeQueueUserWorkItem и что именно означает "не распространяет вызывающий стек"?

Я читаю и изучаю ThreadScheduler и статьи вокруг Tasks и сталкиваюсь с функцией ThreadPool.UnsafeQueueUserWorkItem используемой в одном из примеров MSDN о собственных ThreadSchedulers. В описании MSDN об UnsafeQueueUserWorkItem есть большое предупреждение о том, что функция может быть дырой в безопасности и что она "не распространяется на вызывающий стек".

Единственная ссылка - QueueUserWorkItem которая - от имени - кажется, является "безопасным партнером"? но не упоминает ничего о вызовах стеков.

Что это значит для распространения стека? Скопировать его до начала работы? Почему в любом случае потребуется еще один поток стопки вызывающего потока? Я бы предположил, что они начинаются со свежего и пустого стека. В конце концов, когда функция потока возвращается, она не продолжает выполнять функцию, планирующую задачу, правильно?

Ответ 1

Это деталь реализации CAS, Security Access Security. Который может проверить, имеет ли поток достаточные права для выполнения операции. Это имеет значение только в том случае, если код работает в ограниченной среде безопасности, не работает с полным доверием или в изолированной программной среде.

Сантехника, которая делает эту работу, сложна, и я могу только приблизиться к ее работе. Класс ExecutionContext является ключевым, он определяет контекст безопасности, в котором выполняется код. Все становится трудным, когда поток, который работает с ограниченными правами, запускает другой поток. Ясно, что другой поток должен запускаться с теми же ограничениями, что и исходный поток. CAS зависит от возможности выполнять стеки, чтобы обнаружить ограничения. Это сложно в другом потоке, у него есть свой собственный стек.

Метод ExecutionContext.Capture() выполняет здесь важную роль. Он создает копию контекста вызывающего потока, включая создание стека, чтобы создать "сжатый" стек обнаруженных атрибутов безопасности. Затем новый поток запускается с этим захваченным контекстом.

ThreadPool.UnsafeQueueUserWorkItem() пропускает вызов Capture(). Нить threadpool будет работать с контекстом выполнения по умолчанию.

Это оптимизация, Capture() не является дешевым методом. Это имеет значение в виде программы, которая зависит от потоков ТП, чтобы ускорить работу. Веб-сервер подскакивает. Также тип кода, который использует этот метод, вы видите, что он используется во внутренних методах в пространстве имен System.Net, например.

Очевидно, что это небезопасно, оно не работает с ограничениями CAS исходного потока.