BackgroundWorker и Timer, обрабатывающие по одному элементу за раз - PullRequest
0 голосов
/ 23 июня 2009

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

Моя проблема в том, что я не знаю, как обращаться с таймером во время выполнения фоновой задачи. Например, если таймер установлен на 10 секунд, а фоновый работник все еще работает, я хочу, чтобы таймер пропустил выполнение другого фонового работника до следующей итерации.

Кроме того, информация для каждой задачи хранится в очереди (элемент управления ListView), и я передаю ListViewItem фоновому работнику. Мне любопытно, если передача ListViewItem имеет какие-либо побочные эффекты.

Спасибо!

Ответы [ 6 ]

1 голос
/ 23 июня 2009

Вы можете хранить готовые к обработке файлы в другой очереди (например, Queue ), и BgWorker будет постоянно опрашивать эту очередь. Вы также можете получить лучшую производительность, меньше времени простоя. Вам нужно будет защитить очередь (с помощью монитора) и заставить BgWorker использовать Monitor.Wait, когда очередь пуста.

Чтобы понять, ищите ответ Марка Гравелла на этот вопрос .

0 голосов
/ 23 июня 2009

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

  • Очередь должна быть поточно-ориентированной, и вполне вероятно, что вы захотите, чтобы фоновый работник заблокировал ее, если очередь пуста, и проснулся, когда элемент стал доступен. Я уверен, что Сомоне уже сделал такую ​​хорошую очередь.
  • Элементы, которые вы публикуете в очереди, будут обрабатываться в другом потоке (фоновый работник). Убедитесь, что это сделано потокобезопасным способом (например, не размещайте элементы в очереди, которые будут изменять как основное приложение, так и фоновый работник)

Другой и более простой подход -

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

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

0 голосов
/ 23 июня 2009

В вашем обработчике Timer.Tick проверьте свойство BackgroundWorker.IsBusy , чтобы определить, готово ли оно к другой работе или нет. Если нет, просто пропустите задание и дождитесь следующего тика.

0 голосов
/ 23 июня 2009

Самое простое, что вы можете сделать, это сделать всю работу (включая проверку папки) внутри вашего BackgroundWorker: проверьте, есть ли у вас что-то сделать, если да, сделайте это, если нет, используйте Sleep (время) или WaitOne (время) ) приостановить поток на некоторое время.

Я не думаю, что вам нужна потокобезопасная очередь, потому что папка в любом случае обновляется асинхронно. Так что вам нужен только один поток, , но , вам нужен способ остановить его. Вот почему AutoResetEvent.WaitOne (time) будет лучше, чем Sleep (time) - вы можете сообщить о событии из основного потока, чтобы завершить работу фонового рабочего процесса раньше.

0 голосов
/ 23 июня 2009

Является ли BackgroundWorker.IsBusy свойство тем, что вы ищете?

0 голосов
/ 23 июня 2009

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

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

...