Производственные последствия BeginInvoke - PullRequest
6 голосов
/ 18 марта 2010

Я унаследовал код, где 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.

Ответы [ 4 ]

4 голосов
/ 19 марта 2010

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

Теперь, когда мы видим код, становится ясно, что это просто способ переместить некоторую инициализацию из 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 вызывается из основного потока, а не из фонового потока.

2 голосов
/ 18 марта 2010

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

1 голос
/ 19 марта 2010

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

Вот довольно хороший справочный пример здесь в разделе "Потоково-безопасные вызовы элемента управления Windows Forms" .

1 голос
/ 19 марта 2010

В этом сценарии я подозреваю, что вызов выглядит так:

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

Происходит следующее: некоторый код будет выполняться в потоке пула потоков и обновлять элемент управления в потоке, который создал элемент управления, тогда как если используется Control.Invoke, некоторый код будет выполняться в потоке, который создал элемент управления, и также обновит элемент управления в этом потоке.

...