2010-03-18 6 views
6

Я унаследовал код, в котором BeginInvoke вызывается из основного потока (а не фонового потока, который обычно является шаблоном). Я пытаюсь понять, что он на самом деле делает в этом сценарии.Последствия для работы BeginInvoke

Вызывается ли метод, вызываемый в BeginInvoke, в строке сообщений, которые попадают в окно? Документы говорят asynchronously, так что это мое предположение.

Как фреймворк определяет приоритеты, когда следует начинать метод, называемый BeginInvoke?

Edit: код выглядит следующим образом:

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.

ответ

4

редактировать

Теперь, когда мы видим код, то становится ясно, что это просто способ переместить некоторые инициализации из Form_Load, но до сих пор это произошло до того, как пользователь может взаимодействовать с формой.

Звонок в BeginInvoke находится внутри Form_load и не вызывается на другой объект, поэтому это вызов Form.BeginInvoke. Так что происходит.

  1. Form_Load проходит делегат Form.BeginInvoke, это помещает сообщение в очередь сообщений формы, которая является впереди всех введенных пользователем сообщений. Он устанавливает курсор на курсор ожидания.
  2. Form_Load возвращается, а остальная форма инициализации формы может быть завершена, форма, скорее всего, станет видимой на этом этапе.
  3. Как только код попадает в насос сообщений, первое, что видит в очереди, является делегатом, поэтому он запускает это.
  4. , когда делегат завершает работу, он переключает курсор на обычный курсор и возвращает
  5. прибыль!

оригинальный пост ниже


Я зависит от объекта, который вы называете BeginInvoke на. Если объект получен из Control, тогда Control.BeginInvoke будет запускаться в потоке, который создал элемент управления. См. Ответ JaredPar.

Но есть еще один образец для использования 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 вызывается из основного потока, а не из фонового потока.

+0

@ Джона Кноллера, вы говорите, что в моем сценарии BeginInvoke несет вес контекста контекста потока? – AngryHacker

+0

@AngryHacker: Нет, теперь, когда вы показали свой код, ясно, что это только PostMessage, как описано в JaredPar, ваш BeginInvoke - это метод в форме и, таким образом, будет _not_ запускать делегат в отдельном потоке. –

2

В случае, когда BeginInvoke вызывается в потоке пользовательского интерфейса, он все равно будет проходить процесс отправки сообщения Windows в очередь сообщений, где сообщение будет ждать обработки. Делегат будет работать, когда сообщение будет обработано. Это сообщение не имеет приоритета ни в коем случае, которое отличается от того, что оно вызывается из фонового потока.

+1

Это не ждет. –

+0

@nobugz, ужасная формулировка с моей стороны. Я пытался сказать, что само сообщение будет сидеть в очереди, где он ждет обработки, а не ожидания вызывающего. Очистил язык. – JaredPar

+0

Вы уверены в этом? BeginInvoke - это PostMessage, а не SendMessage или SendNotifyMessage? –

1

В этом случае я подозреваю, что вызов выглядит следующим образом:

private void Button1_Click(object sender, ButtonClickEventArgs e) 
{ 
    Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */)); 
} 

Что происходит, что некоторый код будет работать на на Threadpool нить, и обновить контроль над потоком, который создал контроль, тогда как если Control.Invoke был использован, некоторый код будет работать в потоке, который создал элемент управления, и обновить элемент управления в этом потоке.

1

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

Существует довольно хороший ссылочный пример here в разделе «Потоки для управления Windows Forms Control».

Смежные вопросы