Я наследовал код, откуда BeginInvoke называют основного потока (не фоновый поток, который обычно является шаблоном). Я пытаюсь понять то, что это на самом деле делает в этом сценарии.
Метод, называемый в BeginInvoke, входят в строку сообщений, которые сводятся к окну? В документах говорится asynchronously
, таким образом, это - мое предположение.
Как платформа располагает по приоритетам, когда начать метод, названный BeginInvoke?
Править: Код похож на это:
System.Action<bool> finalizeUI = delegate(bool open)
{
try
{
// do somewhat time consuming stuff
}
finally
{
Cursor.Current = Cursors.Default;
}
};
Cursor.Current = Cursors.WaitCursor;
BeginInvoke(finalizeUI, true);
Это происходит в событии Form_Load.
Теперь, когда мы видим код, становится ясно, что это всего лишь способ перенести некоторую инициализацию из Form_Load, но все же выполнить ее до того, как пользователь сможет взаимодействовать с формой.
Вызов BeginInvoke
находится внутри Form_load и не вызывается для другого объекта, поэтому это вызов Form.BeginInvoke. Так вот что происходит.
исходное сообщение ниже
Я зависит от объекта, для которого вы вызываете BeginInvoke. Если объект является производным от Control
, то Control.BeginInvoke будет выполняться в потоке, создавшем элемент управления. См. Ответ Джаредпара.
Но есть еще один шаблон использования BeginInvoke. если объект является делегатом, то BeginInvoke запускает обратный вызов в отдельном потоке, который может быть создан специально для этой цели.
public class Foo
{
...
public Object Bar(object arg)
{
// this function will run on a separate thread.
}
}
...
// this delegate is used to Invoke Bar on Foo in separate thread, this must
// take the same arguments and return the same value as the Bar method of Foo
public delegate object FooBarCaller (object arg);
...
// call this on the main thread to invoke Foo.Bar on a background thread
//
public IAsyncResult BeginFooBar(AsyncCallback callback, object arg)
{
Foo foo = new Foo();
FooBarCaller caller = new FooBarCaller (foo.Bar);
return caller.BeginInvoke (arg);
}
Этот шаблон является одной из причин того, что BeginInvoke вызывается из основного потока, а не из фонового потока.
До повсеместного использования BackgroundWorker вам приходилось выполнять обратную синхронизацию с потоком пользовательского интерфейса, прежде чем выполнять какие-либо операции с элементами управления, созданными в потоке пользовательского интерфейса (т.е. почти каждый элемент управления ).
Здесь есть неплохой справочный пример , в разделе «Потоко-безопасные вызовы элемента управления Windows Forms» .
В этом сценарии я подозреваю, что вызов выглядит так:
private void Button1_Click(object sender, ButtonClickEventArgs e)
{
Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */));
}
Что происходит, так это то, что некоторый код будет выполняться в потоке пула потоков и обновлять элемент управления в потоке, создавшем элемент управления, тогда как если Control .Invoke, какой-то код будет выполняться в потоке, создавшем элемент управления, а также обновлять элемент управления в этом потоке.
В случае, если BeginInvoke вызывается в потоке пользовательского интерфейса, он все равно будет проходить процесс отправки сообщения Windows в очередь сообщений, где сообщение будет ждать до быть обработанным. Делегат будет запущен после обработки сообщения. Это сообщение не имеет приоритетов, отличных от того, что оно вызывается из фонового потока.