ли работать Вы задача (и не Task
) как так:Переключение контекста синхронизации означает, что работа будет выполняться в потоке, которому принадлежит контекст синхронизации?
public async void button1_click(...)
{
await Task.Run(...);
}
или использование на старых методов, где вы называете InvokeRequired
, чтобы проверить, есть ли необходимость вызова текущей операции на другой контекст синхронизации, а затем вызовите Control.Invoke
(например, в случае WinForms), операция выполняется с использованием захваченного контекста синхронизации, если таковой имеется.
Однако, какая из двух вещей означает это?
Если вы запрашиваете задание должно выполняться в потоке пула потоков с использованием любого из методов, будь то старый или новый, это означает, что:
Когда поток получает от земли, переключение контекста синхронизации означает, что он будет ждать, когда поток, которому принадлежит контекст синхронизации, будет выполнять кусок кода? В случае контекста синхронизации, используемого пользовательским интерфейсом, означает ли это, что поток пула потоков отправит ответное действие в очередь сообщений в потоке пользовательского интерфейса и даст?
ИЛИ
Или это означает, что пул потоков поток будет выполнить действие, но там будет просто переключатель опорной переменной (
System.Threading.ExecutionContext.SynchronizationContext
), который содержит контекст синхронизации, и в качестве такового, в контексте синхронизации это только кооперативная дисциплина, которую нитки соглашаются придерживаться? Работа по-прежнему будет выполняться потоком пула потоков?Конечно, по кооперативной дисциплине *, я не имею в виду, что все будет работать хорошо, даже если беспорядочная нить решила не переключать контекст синхронизации там, где это требовалось. Я имею в виду, что поток, не владеющий контекстом синхронизации, по-прежнему может выполняться, если ссылка на контекст синхронизации изменяется на правую.
От чтения исходного кода AsyncMethodBuilder<TResult>.Start
, System.Threading.Tasks.Task.ExecuteWithThreadLocal
и System.Threading.ExecutionContext.RunInternal
метода, представляется весьма вероятным, что ответ # 2, но я не уверен.
UPDATE
Вот почему и я полагаю, # 2, скорее всего, но я хотел бы исправить.
Если вы просто возьмете приложение Windows Forms и нажмете на него кнопку и запустите код, показанный на картинке в событии клика, вы можете увидеть стек вызовов, который выглядит как мой, как показано на том же снимке ,
Я следовал исходный код каждого метода в стеке вызовов. Я заметил, что переключатель контекста происходит в методе System.Threading.ExecutionContext.RunInternal
. Это происходит потому, что метод System.Threading.Tasks.ExecuteWithThreadLocal
передает значение true
для последнего параметра его вызова методу System.Threading.ExecutionContext.Run
. См. line 2823.
Однако после этого вызов продолжается без отправки сообщений в очередь сообщений потока пользовательского интерфейса, и когда он, наконец, достигает метода System.Threading.Tasks.Task<TResult>.InnerInvoke
, метод вызывает делегата.
Если ответ №1, если вы могли бы показать мне, где происходит проводка сообщений, я буду прыгать с радостью и сегодня узнаю что-то захватывающее в контексте синхронизации.
Это происходит в методе ExecutionContext.SetExecutionContext
?
И если ответ №2, и если бы вы могли подтвердить это, то и я буду петь песню в честь моего открытия.
Side Примечание
Я сделал эту программу, чтобы проверить что-то другое, хотя. Я хотел видеть где переключают контекст синхронизации, если требуется , как:
- До достижения
await
заявление; и- После заявления
await
, т. е. на ответный вызов продолжения.И мои выводы удовлетворительно показали мне ответы на вопросы .
Для любого любопытного, переключатель выполнен в
Start
методыAsyncMethodBuilder
«s для любого кода, который перед тем выраженияawait
.Для кода, который находится после, существует более одного пути. Один из путей изображен в этом стеке вызовов, который показан на рисунке выше.
Ваше предположение неверно, Control.Begin/Invoke() делает ** не ** использовать контекст синхронизации.Это наоборот, это SynchronizationContext, который использует Control.Begin/Invoke(). В частности, экземпляр WindowsFormsSynchronizationContext, который устанавливается автоматически, когда вы создаете элемент управления или вызываете Application.Run(). Ваш вопрос перестает иметь смысл с этой важной деталью. –
@ HansPassant Я думаю о том, что вы сказали. –
@HansPassant Я держу вашу коррекцию в хорошем положении. Мои знания о вещах непростительно ограничены. Я не уверен, как я могу исправить это немедленно и перефразировать мой вопрос. Как и следовало бы, Gobbledygook, суть моего вопроса заключается в следующем: до того, как поток потока потока выполнит действие, если необходимо, чтобы контекст синхронизации был захвачен, это заставляет поток пула потоков отказаться от своего временного фрагмента процессора и делегировать эту работу вернуться к потоку пользовательского интерфейса? Или это означает, что поток пула потоков выполнит действие, предваряющее его с изменением значения ссылочной переменной, которая содержит контекст синхронизации? –