Я столкнулся с необходимостью использовать многопоточность в моем приложении с графическим интерфейсом 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 );
}
Однако есть несколько вещей, которые мне нужны, чтобы разобраться и разобраться
Будет ли фоновый рабочий поток облегчить мою многопоточную жизнь?
Да, очень сильно. Это помогает вам справиться с тем фактом, что вы не можете обновить пользовательский интерфейс из рабочего потока. В частности, событие ProgressChanged позволяет отображать прогресс, а событие RunWorkerCompleted позволяет использовать результаты рабочего потока для обновления пользовательского интерфейса, не прибегая к решению проблемы многопоточности.
Зачем мне нужен e-> Result?
Чтобы вернуть результат работы, которую вы проделали, в поток пользовательского интерфейса. Вы получаете значение обратно в свой обработчик событий RunWorkerCompleted, e-> Result свойство. Из которого вы затем обновите пользовательский интерфейс с результатом.
Для чего передаются аргументы в функцию?
Указывать рабочему потоку, что делать, необязательно. В остальном, идентично передаче аргументов любому методу, просто более неловко, так как вы не можете выбрать аргументы. Обычно вы передаете какое-то значение из вашего пользовательского интерфейса, например, используйте небольшой вспомогательный класс, если вам нужно передать более одного. Всегда отдавайте предпочтение этому, а не пытайтесь получить значения UI на рабочем месте, это очень хлопотно.
Что я должен сделать в моем CPUHungryFunction ()?
Сжечь циклы процессора, конечно. Или вообще делайте что-то, что занимает много времени, например, запрос к базе данных. Который не сжигает циклы процессора, но занимает слишком много времени, чтобы позволить потоку пользовательского интерфейса обесточиться, ожидая результата. Грубо говоря, когда вам нужно сделать что-то, что занимает больше секунды, вы должны выполнить это в рабочем потоке, а не в потоке пользовательского интерфейса.
Что если мой CPUHungryFunction () имеет цикл while, который зацикливается бесконечно?
Тогда ваш работник никогда не завершит и никогда не даст результата. Это может быть полезно, но это не распространено. Обычно вы не используете BGW для этого, просто обычный поток, для свойства IsBackground которого установлено значение true.
Имею ли я контроль над временем процессора, которое получает мой рабочий поток?
У вас есть некоторые, искусственно замедляя их, вызывая Thread.Sleep (). Это не обычное дело, цель запуска рабочего потока — это выполнение работы. Поток, который спит, использует дорогой ресурс непродуктивно.
Может ли более конкретно контролировать количество циклов в течение установленного периода? Я не хочу использовать циклы ЦП 1000 раз в секунду, когда мне нужно только 30 циклов в секунду.
Так же, как и выше, вам придется спать. Сделайте это, выполнив цикл 30 раз, а затем поспите секунду.
Нужно ли контролировать скорость обновления графического интерфейса?
Да, это очень важно. ReportProgress () может быть пожарным шлангом, генерирующим тысячи обновлений пользовательского интерфейса в секунду. Вы можете легко столкнуться с проблемой, когда поток пользовательского интерфейса просто не справится с этой скоростью. Вы заметите, что поток пользовательского интерфейса перестает выполнять свои обычные обязанности, такие как рисование пользовательского интерфейса и реагирование на ввод. Потому что он продолжает иметь дело с другим запросом вызова для запуска обработчика события ProgressChanged. Побочным эффектом является то, что интерфейс выглядит замороженный, Вы получили именно ту проблему, которую пытались решить с работником. На самом деле он не заморожен, просто выглядит так, он все еще работает с обработчиком событий. Но ваш пользователь не увидит разницы.
Следует помнить, что ReportProgress () нужно только для того, чтобы человеческие глаза были счастливы. Который не может видеть обновления, которые происходят чаще, чем 20 раз в секунду. Кроме того, это просто превращается в нечитаемое размытие. Так что не тратьте время на обновления пользовательского интерфейса, которые просто бесполезны в любом случае. Вы также автоматически избежите проблемы с пожарным шлангом. Настройка частоты обновления — это то, что вы должны программировать, она не встроена в BGW.
Я постараюсь ответить вам вопрос за вопросом
DoWork
исполняетRunWorkerCompleted
событие внутриRunWorkerCompletedEventArgs
DoWorkEventArgs
в конце концовRunWorkerAsync(Object)
)WorkerReportProgress
свойство установлено вПожалуйста, обратитесь к документации MSDN на BackgroundWorker а также Нить классы