Некоторые вопросы по многопоточности и фоновым рабочим потокам в форме Windows

Я столкнулся с необходимостью использовать многопоточность в моем приложении с графическим интерфейсом Windows C ++. Из моих исследований по теме кажется, что фоновые рабочие потоки — это путь для моих целей. Согласно примеру кода у меня есть

System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e)
{
BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
e->Result = SomeCPUHungryFunction( safe_cast<Int32>(e->Argument), worker, e );
}

Однако есть несколько вещей, которые мне нужны, чтобы разобраться и разобраться

  • Будет ли фоновый рабочий поток облегчить мою многопоточную жизнь?
  • Зачем мне нужен e-> Result?
  • Для чего нужны аргументы, передаваемые в функцию backgroundWorker1_DoWork?
  • Какова цель параметра safe_cast (e-> Argument)?
  • Что я должен сделать в моем CPUHungryFunction ()?
  • Что если мой CPUHungryFunction () имеет цикл while, который зацикливается бесконечно?
  • Имею ли я контроль над временем процессора, которое получает мой рабочий поток?
  • Может ли более конкретно контролировать количество циклов в течение установленного периода? Я не хочу использовать циклы ЦП 1000 раз в секунду, когда мне нужно только 30 циклов в секунду.
    * Нужно ли контролировать скорость обновления графического интерфейса?

2

Решение

Будет ли фоновый рабочий поток облегчить мою многопоточную жизнь?

Да, очень сильно. Это помогает вам справиться с тем фактом, что вы не можете обновить пользовательский интерфейс из рабочего потока. В частности, событие ProgressChanged позволяет отображать прогресс, а событие RunWorkerCompleted позволяет использовать результаты рабочего потока для обновления пользовательского интерфейса, не прибегая к решению проблемы многопоточности.

Зачем мне нужен e-> Result?

Чтобы вернуть результат работы, которую вы проделали, в поток пользовательского интерфейса. Вы получаете значение обратно в свой обработчик событий RunWorkerCompleted, e-> Result свойство. Из которого вы затем обновите пользовательский интерфейс с результатом.

Для чего передаются аргументы в функцию?

Указывать рабочему потоку, что делать, необязательно. В остальном, идентично передаче аргументов любому методу, просто более неловко, так как вы не можете выбрать аргументы. Обычно вы передаете какое-то значение из вашего пользовательского интерфейса, например, используйте небольшой вспомогательный класс, если вам нужно передать более одного. Всегда отдавайте предпочтение этому, а не пытайтесь получить значения UI на рабочем месте, это очень хлопотно.

Что я должен сделать в моем CPUHungryFunction ()?

Сжечь циклы процессора, конечно. Или вообще делайте что-то, что занимает много времени, например, запрос к базе данных. Который не сжигает циклы процессора, но занимает слишком много времени, чтобы позволить потоку пользовательского интерфейса обесточиться, ожидая результата. Грубо говоря, когда вам нужно сделать что-то, что занимает больше секунды, вы должны выполнить это в рабочем потоке, а не в потоке пользовательского интерфейса.

Что если мой CPUHungryFunction () имеет цикл while, который зацикливается бесконечно?

Тогда ваш работник никогда не завершит и никогда не даст результата. Это может быть полезно, но это не распространено. Обычно вы не используете BGW для этого, просто обычный поток, для свойства IsBackground которого установлено значение true.

Имею ли я контроль над временем процессора, которое получает мой рабочий поток?

У вас есть некоторые, искусственно замедляя их, вызывая Thread.Sleep (). Это не обычное дело, цель запуска рабочего потока — это выполнение работы. Поток, который спит, использует дорогой ресурс непродуктивно.

Может ли более конкретно контролировать количество циклов в течение установленного периода? Я не хочу использовать циклы ЦП 1000 раз в секунду, когда мне нужно только 30 циклов в секунду.

Так же, как и выше, вам придется спать. Сделайте это, выполнив цикл 30 раз, а затем поспите секунду.

Нужно ли контролировать скорость обновления графического интерфейса?

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

Следует помнить, что ReportProgress () нужно только для того, чтобы человеческие глаза были счастливы. Который не может видеть обновления, которые происходят чаще, чем 20 раз в секунду. Кроме того, это просто превращается в нечитаемое размытие. Так что не тратьте время на обновления пользовательского интерфейса, которые просто бесполезны в любом случае. Вы также автоматически избежите проблемы с пожарным шлангом. Настройка частоты обновления — это то, что вы должны программировать, она не встроена в BGW.

3

Другие решения

Я постараюсь ответить вам вопрос за вопросом

  1. да
  2. DoWork — это пустой метод (и так должно быть). Также DoWork исполняет
    в другом потоке от вызывающего, так что вам нужно иметь
    способ вернуть что-то в вызывающий поток. Э-> Результат
    параметр будет передан в RunWorkerCompleted событие внутри
    RunWorkerCompletedEventArgs
  3. Аргумент отправителя — это сам фоновый работник, который вы можете использовать
    вызывать события для потока пользовательского интерфейса, DoWorkEventArgs в конце концов
    содержит параметры, переданные из вызывающего потока (тот, кто имеет
    называется RunWorkerAsync(Object))
  4. Все, что вам нужно сделать. Обращая внимание на пользовательский интерфейс
    элементы, которые не доступны из потока DoWork. Обычно один
    рассчитать процент выполненной работы и обновить интерфейс пользователя (прогресс
    bar или что-то подобное) и вызвать ReportProgress для связи с
    поток пользовательского интерфейса. (Должен иметь WorkerReportProgress свойство установлено в
    Правда)
  5. Ничто не работает бесконечно. Вы всегда можете отключить шнур.
    Серьезно, это просто еще один поток, ОС заботится об этом и
    уничтожает все, когда ваше приложение заканчивается.
  6. Не уверен, что вы имеете в виду с этим, но это, вероятно, связано
    к следующему вопросу
  7. Вы можете использовать методы Thread.Sleep или Thread.Join для освобождения
    Процессорное время после одного цикла. Точное время для сна должно быть в порядке
    настроены в зависимости от того, что вы делаете, нагрузка на текущий
    система и сырая скорость вашего процессора

Пожалуйста, обратитесь к документации MSDN на BackgroundWorker а также Нить классы

1

По вопросам рекламы [email protected]