WedX - журнал о программировании и компьютерных науках

Вызов (делегат)

Кто-нибудь может объяснить это заявление, написанное по этой ссылке

Invoke(Delegate):

Выполняет указанный делегат в потоке, которому принадлежит дескриптор окна, лежащего в основе элемента управления.

Может ли кто-нибудь объяснить, что это означает (особенно жирный), я не могу это четко понять



Ответы:


1

Ответ на этот вопрос заключается в том, как работают элементы управления C #.

Элементы управления в Windows Forms привязаны к определенному потоку и не являются потокобезопасными. Следовательно, если вы вызываете метод элемента управления из другого потока, вы должны использовать один из методов вызова элемента управления для маршалинга вызова в соответствующий поток. Это свойство можно использовать, чтобы определить, нужно ли вызывать метод invoke, что может быть полезно, если вы не знаете, какой поток владеет элементом управления.

Из Control. InvokeRequired

По сути, Invoke гарантирует, что вызываемый вами код выполняется в потоке, в котором «живет» элемент управления, эффективно предотвращая перекрестные исключения.

С исторической точки зрения в .Net 1.1 это действительно было разрешено. Это означало, что вы можете попробовать выполнить код в потоке «GUI» из любого фонового потока, и это в основном сработает. Иногда это просто приводило к завершению вашего приложения, потому что вы фактически прерывали поток графического интерфейса пользователя, пока он делал что-то еще. Это исключение Cross Threaded Exception - представьте, что вы пытаетесь обновить TextBox, пока графический интерфейс рисует что-то еще.

  • Какое действие имеет приоритет?
  • Возможно ли, чтобы и то и другое произошло одновременно?
  • Что происходит со всеми другими командами, которые необходимо запустить графическому интерфейсу?

Фактически, вы прерываете очередь, что может иметь множество непредвиденных последствий. Invoke - это, по сути, «вежливый» способ поместить то, что вы хотите сделать в эту очередь, и это правило применялось начиная с .Net 2.0 и далее через брошенный InvalidOperationException.

Чтобы понять, что на самом деле происходит за кулисами и что подразумевается под «потоком графического интерфейса», полезно понять, что такое Message Pump или Message Loop.

Фактически, на этот вопрос уже есть ответ в вопросе «Что такое насос сообщений», и он рекомендуется. прочтите, чтобы понять реальный механизм, с которым вы связаны при взаимодействии с элементами управления.

Другое чтение, которое может оказаться полезным, включает:

Что случилось с Begin Invoke

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

и, для более подробного обзора кода с репрезентативной выборкой:

Недействительные межпоточные операции

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type

public void SetText(Control control, string text) {
    if (control.InvokeRequired) {
        control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
    } else {
        control.Text=text;      // the "functional part", executing only on the main thread
    }
}

Когда вы оцените InvokeRequired, вы можете рассмотреть возможность использования метода расширения для упаковки этих вызовов. Это подробно описано в вопросе о переполнении стека Требуется очистка кода, помеченного с помощью Invoke .

Существует также дополнительная история исторического развития, которая может представлять интерес.

05.02.2013

2

Элемент управления или объект окна в Windows Forms - это просто оболочка вокруг окна Win32, идентифицируемого дескриптором (иногда называемым HWND). Большинство действий, которые вы делаете с элементом управления, в конечном итоге приведет к вызову Win32 API, который использует этот дескриптор. Дескриптор принадлежит потоку, который его создал (обычно главному потоку), и не должен управляться другим потоком. Если по какой-то причине вам нужно что-то сделать с элементом управления из другого потока, вы можете использовать Invoke, чтобы попросить основной поток сделать это от вашего имени.

Например, если вы хотите изменить текст метки из рабочего потока, вы можете сделать что-то вроде этого:

theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
05.02.2013
  • Вы можете объяснить, почему кто-то сделал что-то подобное? this.Invoke(() => this.Enabled = true); Все, к чему относится this, несомненно, находится в текущем потоке, верно? 01.02.2017
  • @KyleDelaney, объект не находится в потоке, и текущий поток не обязательно является потоком, создавшим объект. 05.02.2017

  • 3

    Если вы хотите изменить элемент управления, это необходимо сделать в потоке, в котором этот элемент управления был создан. Этот Invoke метод позволяет вам выполнять методы в связанном потоке (потоке, которому принадлежит базовый дескриптор окна элемента управления).

    В приведенном ниже примере thread1 выдает исключение, потому что SetText1 пытается изменить textBox1.Text из другого потока. Но в thread2 действие в SetText2 выполняется в потоке, в котором был создан TextBox.

    private void btn_Click(object sender, EvenetArgs e)
    {
        var thread1 = new Thread(SetText1);
        var thread2 = new Thread(SetText2);
        thread1.Start();
        thread2.Start();
    }
    
    private void SetText1() 
    {
        textBox1.Text = "Test";
    }
    
    private void SetText2() 
    {
        textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
    }
    
    05.02.2013
  • Мне очень нравится этот подход, он скрывает характер делегатов, но в любом случае это хороший ярлык. 27.08.2015

  • 4

    На практике это означает, что делегат гарантированно будет вызван в основном потоке. Это важно, потому что в случае элементов управления Windows, если вы не обновляете их свойства в основном потоке, вы либо не видите изменения, либо элемент управления вызывает исключение.

    Шаблон такой:

    void OnEvent(object sender, EventArgs e)
    {
       if (this.InvokeRequired)
       {
           this.Invoke(() => this.OnEvent(sender, e);
           return;
       }
    
       // do stuff (now you know you are on the main thread)
    }
    
    05.02.2013

    5

    this.Invoke(delegate) убедитесь, что вы вызываете делегата аргументом this.Invoke() в основном потоке / созданном потоке.

    Я могу сказать, что правило Thumb не имеет доступа к элементам управления вашей формы, кроме как из основного потока.

    Возможно, следующие строки имеют смысл использовать Invoke ()

        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.textBox1.InvokeRequired)
            {   
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text = text;
            }
        }
    

    Бывают ситуации, когда вы создаете поток Threadpool (т. Е. Рабочий поток), он будет работать в основном потоке. Он не будет создавать новый поток, потому что основной поток доступен для обработки дальнейших инструкций. Итак, сначала выясните, является ли текущий выполняющийся поток основным потоком, используя this.InvokeRequired, если возвращает true, текущий код выполняется в рабочем потоке, поэтому вызовите this.Invoke (d, new object [] {text});

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

    10.02.2014

    6

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

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

    05.02.2013

    7

    Делегаты по сути являются встроенными Action или Func<T>. Вы можете объявить делегата вне области действия выполняемого вами метода или с помощью выражения lambda (=>); поскольку вы запускаете делегат в методе, вы запускаете его в потоке, который выполняется для текущего окна / приложения, который выделен полужирным шрифтом.

    Пример лямбда

    int AddFiveToNumber(int number)
    {
      var d = (int i => i + 5);
      d.Invoke(number);
    }
    
    05.02.2013

    8

    Это означает, что переданный вами делегат выполняется в потоке, создавшем объект Control (который является потоком пользовательского интерфейса).

    Вам нужно вызвать этот метод, когда ваше приложение является многопоточным и вы хотите выполнить некоторую операцию пользовательского интерфейса из потока, отличного от потока пользовательского интерфейса, потому что, если вы просто попытаетесь вызвать метод элемента управления из другого потока, вы получите System.InvalidOperationException.

    05.02.2013

    9
  • Использование System.Action, которое люди предлагают в других ответах, работает только на framework 3.5+, для более старых версий это отлично работает 20.12.2016
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    © 2024 wedx.ru, WedX - журнал о программировании и компьютерных науках
    Для любых предложений по сайту: wedx@cp9.ru