2013-05-28 3 views
3

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

private void btnAddDir_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) 
     { 
      ThreadStart threadStart = delegate 
      { 
       foreach (string file in SafeFileEnumerator.EnumerateFiles(folderBrowserDialog1.SelectedPath, "*.*", SearchOption.AllDirectories)) 
       { 
        Interlocked.Increment(ref numWorkers); 
        StartBackgroundFileChecker(file); 
       } 
      }; 

      Thread thread = new Thread(threadStart); 
      thread.IsBackground = true; 
      thread.Start(); 
     } 
    } 
    catch (Exception) 
    { } 
} 

private void StartBackgroundFileChecker(string file) 
{ 
    ListboxFile listboxFile = new ListboxFile(); 
    listboxFile.OnFileAddEvent += listboxFile_OnFileAddEvent; 
    BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    backgroundWorker.WorkerReportsProgress = true; 
    backgroundWorker.DoWork += 
    (s3, e3) => 
    { 
     //check my file 
    }; 

    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.RunWorkerAsync(); 
} 

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (Interlocked.Decrement(ref numWorkers) == 0) 
    { 
     //update my UI 
    } 
} 

Когда я проверить этот файл я открыт Wireshark процесс, так что если я выбрать папку с большим количеством файлов, многие Wireshark обрабатываются, и это занимает много места в памяти, как я могу подождать, пока мой BackgroundWorker не закончится, и только потом открыть новый?

+0

Довольно уверен, что уже прокомментировал этот код. Точно такой же совет, переместите петлю foreach внутри рабочего, так что вам понадобится только один BGW. Ожидание потоков - это всегда плохая идея, ваш код будет заторможен. –

ответ

8

Как я понимаю, вы хотите только одного фона рабочего запущен во время , Если это так, то попробуйте это (на основе System.Threading.AutoResetEvent)

//introduce additional field 
private AutoResetEvent _workerCompleted = new AutoResetEvent(false); 
//modify StartBackgroundFileChecker 
private void StartBackgroundFileChecker(string file) 
{ 
    ListboxFile listboxFile = new ListboxFile(); 
    listboxFile.OnFileAddEvent += listboxFile_OnFileAddEvent; 
    BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    backgroundWorker.WorkerReportsProgress = true; 
    backgroundWorker.DoWork += 
    (s3, e3) => 
    { 
     //check my file 
    }; 

    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.RunWorkerAsync(); 
    //new code - wait for completion 
    _workerCompleted.WaitOne(); 
} 
//add completion notification to backgroundWorker_RunWorkerCompleted 
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (Interlocked.Decrement(ref numWorkers) == 0) 
    { 
     //update my UI 
    } 

    //new code - notify about completion 
    _workerCompleted.Set(); 
} 

В этом решении вашего фоновый поток начнется новый BackgroundWorker один за другим - это может быть не оптимальными (вы могли бы избежать BackgroundWorker на все и просто обновить пользовательский интерфейс с помощью Отправки in threadStart делегат)

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

Вот альтернативное решение (на основе System.Threading.Tasks имен):

private void btnAddDir_Click(object sender, EventArgs e) 
{ 
    var selectedPath = folderBrowserDialog1.SelectedPath; 
    Task.Factory.StartNew(() => 
     { 

      var files = Directory.EnumerateFiles(selectedPath, "*.*", SearchOption.AllDirectories); 

      Parallel.ForEach(files, 
          new ParallelOptions 
          { 
            MaxDegreeOfParallelism = 10 // limit number of parallel threads here 
          }, 
          file => 
          { 
           //process file here - launch your process 
          }); 
     }).ContinueWith(
      t => { /* when all files processed. Update your UI here */ } 
      ,TaskScheduler.FromCurrentSynchronizationContext() // to ContinueWith (update UI) from UI thread 
     ); 
} 

Вы можете настроить это решение для ваших конкретных потребностей.

Используемые классы/методы (см MSDN для справки):

  • Task
  • TaskScheduler.FromCurrentSynchronizationContext
  • Parallel.ForEach Метод (IEnumerable, ParallelOptions, действие)
+0

Я думаю, что контрольный номер параллели будет намного лучше – user2214609

0

Может быть что-то вроде этого, вместо Еогеасп сохранить список файлов и после завершения просто взять первый элемент и обновить список

private List<string> _files; 

private void btnAddDir_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) 
     { 

      _files = new List<string>(SafeFileEnumerator.EnumerateFiles(folderBrowserDialog1.SelectedPath, "*.*", SearchOption.AllDirectories)); 

      Interlocked.Increment(ref numWorkers); 
      var file = _files.FirstOrDefault(); 
      if(file != null) 
       StartBackgroundFileChecker(file); 
     } 
    } 
    catch (Exception) 
    { } 
} 

private void StartBackgroundFileChecker(string file) 
{ 
    ListboxFile listboxFile = new ListboxFile(); 
    listboxFile.OnFileAddEvent += listboxFile_OnFileAddEvent; 
    BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    backgroundWorker.WorkerReportsProgress = true; 
    backgroundWorker.DoWork += 
    (s3, e3) => 
    { 
     //check my file 
    }; 

    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.RunWorkerAsync(); 
} 

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (Interlocked.Decrement(ref numWorkers) == 0) 
    { 
     //update my UI 
     _files = _files.Skip(1); 
     var file = _files.FirstOrDefault(); 
     if(file != null) 
      StartBackgroundFileChecker(file); 
    } 
} 
+0

Проблема в том, что я использую EnumerateFiles, чтобы получить все файлы «в процессе», я не хочу ждать, пока не получу все файлы. – user2214609

+0

Вы можете преобразовать его в список строк, и вы получите все файлы в режиме proccess, но каждый файл будет обработан после завершения Backgroundworker. Где работает фоновой рабочий проводник? – jjchiw

+0

Проводная панель открывает процесс через другой класс, где написано // проверяю мой файл – user2214609

Смежные вопросы