等到我的BackgroundWorker完成后才能打开新的BackgroundWorker

use*_*609 3 c# winforms

在我的应用程序中,我在添加到我的列表框之前通过打开Wireshark进程检查我的文件.这是添加目录单击事件,谁获取根文件夹并检查此文件夹和子文件夹中的所有这些文件:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

当我检查这个文件时,我是打开Wireshark过程,所以如果我选择包含许多文件的文件夹,许多Wireshark进程都会选择,这会占用大量内存,我怎么能等到我的BackgroundWorker完成并且只打开新文件?

小智 9

据我了解,您只希望在此时启动单个后台工作人员.如果是这样,那么试试这个(基于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();
}
Run Code Online (Sandbox Code Playgroud)

在该解决方案中,您的后台线程将逐个启动新的BackgroundWorker - 这可能不是最佳的(您可以完全避免使用BackgroundWorker,只需通过threadStart委托中的Dispatch更新UI )

在我看来,更好地控制并行线程的数量,并仍然处理多个但有限数量的线程中的文件.

这是替代解决方案(基于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
        );
}
Run Code Online (Sandbox Code Playgroud)

您可以根据您的特定需求调整此解决方案.

使用的类/方法(参见MSDN以供参考):

  • 任务
  • TaskScheduler.FromCurrentSynchronizationContext
  • Parallel.ForEach方法(IEnumerable,ParallelOptions,Action)