BackgroundWorker不会运行两次 [英] BackgroundWorker won't run twice

查看:70
本文介绍了BackgroundWorker不会运行两次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是相关代码:

Here is the relevant code:

public static ProcessStartInfo psi = new ProcessStartInfo(thecommand);
public static bool workerDone;
public frmMain()
{
   InitializeComponent();
   work1.DoWork += new DoWorkEventHandler(DoProcessing);
}
private void btnProcess_Click(object sender, EventArgs e)
{
   foreach (string loop in fileNamesToProcess)
   {
      Prepare(loop, out thePath, out tempStr, out thecommand, out thearguments);

      //               DoProcessing();
      psi.WindowStyle = ProcessWindowStyle.Minimized;
      psi.Arguments = thearguments;
      psi.FileName = thecommand;

      workerCompleted = false;
      BackgroundWorker work1 = new BackgroundWorker();
      work1.DoWork += new DoWorkEventHandler(DoProcessing);
      work1.RunWorkerCompleted += new RunWorkerCompletedEventHandler
                     (work1_RunWorkerCompleted);
      work1.WorkerReportsProgress = true;
      work1.RunWorkerAsync(psi);

      // Wait for thread to finish
      while (!workerCompleted)
      {
      }

      //  Delete the original
      File.Delete(workFile);
      //  Rename the processed file
      File.Move(outFile, workFile);

      MoveToDoneList();

      work1 = null;

   }
}
private static void DoProcessing(object sender, DoWorkEventArgs e)
{
   Process p = Process.Start(psi);
   //  Wait for it to finish processing before going on
   while (!p.HasExited)
   {
   }
   workerCompleted = true;
}
void work1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    workerCompleted = true;
}


进程p运行正常,workerDone设置为true,foreach循环继续进行,直到再次遇到work1.RunWorkerAsync(),当我收到它仍然很忙且无法再次运行的错误.

使用BackgroundWorker是因为我的DoProcessing是DOS命令,并且我希望保持窗口活动"状态以能够执行Stop(但不能取消worker,只需停止继续进行下一个项目的foreach循环即可).

我看到一个问题,就是我的过程花了太长时间.需要发送偶尔的消息,但是我不能,因为通过声明work1我无法访问work1.ReprtProgress.也许我只需要放弃在线程中运行该进程,如果我想中断它,请使用任务管理器-无论如何我都可以使用.


Process p runs fine, workerDone is set to true, the foreach loop continues until work1.RunWorkerAsync() is encountered again, when I get the error that it is still busy, and cannot be run again.

Using a BackgroundWorker because my DoProcessing is a DOS command and I want to keep my window "alive" to be able to do a Stop (but not cancel the worker, just stop the foreach loop going on to the next item.)

I see a problem in that my process takes too long. Needs to send the occasional message, but I can''t because by declaring the work1 where I do I can''t access work1.ReprtProgress. Maybe I''ll just have to forgo running the process in a thread and if I want to interrupt it, use task manager - is for my own use anyway.

推荐答案

BackgroundWorkers设计为只能运行一次.对于此任务,您应该使用管理外部进程的老式线程.您可以使用Queue< ProcessStartInfo>整理信息,线程可以将项目从队列中拉出,启动进程,等待其结束,然后触发事件.
BackgroundWorkers are designed to run once. For this task, you should use an old fashioned thread which manages the foreign process. You can use a Queue<ProcessStartInfo> to organise the information, and the thread can pull items off the queue, start the process, wait for it to end and then fire an event.


您可以使用后台工作程序很好地执行此操作. ,但您尝试在流程按钮事件处理程序中完成某些工作,而在后台工作程序中仅做一些工作.

试试这个...

*在您的表单上放置一个BackgroundWorker组件.命名为``audioWorker''
*单击它并选择属性
*将WorkerReportsProgress和WorkerSupportsCancellation设置为true
*单击事件并为DoWork,ProgressChanged和RunWorkerCompleted创建事件处理程序

将新类添加到您的项目.称之为ProcessAudioStartArguments

You can do this using a background worker fine, but you''re trying to do some of the work in the process button event handler and only some in the background worker.

Try this...

* Drop a BackgroundWorker component on your form. Name it ''audioWorker''
* Click on it and choose properties
* Set WorkerReportsProgress and WorkerSupportsCancellation to true
* Click on events and create event handlers for DoWork, ProgressChanged and RunWorkerCompleted

Add a new class to your project. Call it ProcessAudioStartArguments

/// <summary>
/// A class to pass as an argument to the DoWork method of the background
/// worker
/// </summary>
public class ProcessAudioStartArguments
{
    /// <summary>
    /// ctor
    /// </summary>
    /// <param name="files">List of file names to process</param>>
    public ProcessAudioStartArguments(List<ProcessStartInfo> files)
    {
        this.FilesToProcess = files;
    }
    /// <summary>
    /// The list of files to delete
    /// </summary>
    public List<ProcessStartInfo> FilesToProcess { get; private set; }
}



然后,您的实际代码应如下所示..

*建立参数列表以发送给后台工作者
*启动工作程序,传入我们的自定义参数对象



Your actual code should then look something like this..

* Build up a list of arguments to send to the background worker
* Start the worker, pass in our custom arguments object

private void btnProcess_Click(object sender, EventArgs e)
{
   List<ProcessStartInfo> files = new List<ProcessStartInfo>();

   // Prepare your arguments to send to the worker...
   foreach (string loop in fileNamesToProcess)
   {
      Prepare(loop, out thePath, out tempStr, out thecommand, out thearguments);

      ProcessStartInfo psi = new ProcessStartInfo();
      psi.WindowStyle = ProcessWindowStyle.Minimized;
      psi.Arguments = thearguments;
      psi.FileName = thecommand;

  files.Add(psi);
   }

   ProcessAudioStartArguments arguments = new ProcessAudioStartArguments(files);
   audioWorker.RunWorkerAsync(arguments);
}



*在工作线程中执行所有处理.检查取消情况,报告进度等



* Do all processing in the worker thread. Check for cancellations, report on progress etc

private void audioWorker_DoWork(object sender, DoWorkEventArgs e)
{
   ProcessAudioStartArguments arguments = (ProcessAudioStartArguments)e.Argument;
   foreach(ProcessStartInfo psi in arguments.FilesToProcess)
   {
     if (audioWorker.CancellationPending)
         break;

     // Some sort of progress reporting...
     var displayText = string.Format(Resources.ProcessingFile, Path.GetFileName(psi.FileName));
     audioWorker.ReportProgress(step, displayText);

     Process p = Process.Start(psi);
     p.WaitForExit();

     // Some sort of check for success? Return code of process?

     // Delete the original
     File.Delete(workFile);
     //  Rename the processed file
     File.Move(outFile, workFile);
   }
   e.Result = someObj // Report on the success of the processing...?
}



处理进度报告...



Handle progress reporting...

void audioWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
   string currentFile = e.UserState.ToString();

   // Some sort of process window to display percentage done etc...
   progressWindow.SetText(currentFile);
   progressWindow.StepTo(e.ProgressPercentage);
}



因此,将所有工作留给后台工作人员,您只需将其启动一次,然后传递一个arguments对象即可为它提供完成工作所需的所有信息.

我在文章安全删除.NET [



So leave all the work to the background worker, you just start it once and pass in an arguments object that gives it all the information it requries to complete the job.

I do something similar in my article Secure Delete .NET[^].

HTH


在您的代码中可以看到几个问题.

第一个,最明显的一个是,您每次都在循环中为DoWork分配一个新的事件处理程序,但是您不会在任何地方取消分配它.

第二件事是,当您希望尝试在后台线程中执行某项操作时,foreach内部的while循环意味着您已经在其中创建了一个紧密的循环,从而阻塞了主线程.因此,您已经阻塞了主线程.
There are several issus that I can see with your code.

The first, most obvious one, is that you are allocating a new event handler for DoWork in the loop every time, but you don''t deallocate it anywhere.

The second thing is that while you are looking to try and do something in a background thread, the while loop inside your foreach means that you''ve created a tight loop in there which chokes the primary thread. As a result of this, you''ve blocked the main thread.


这篇关于BackgroundWorker不会运行两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆