Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用按钮启动和停止连续运行的后台工作程序_C#_Winforms_Backgroundworker - Fatal编程技术网

C# 如何使用按钮启动和停止连续运行的后台工作程序

C# 如何使用按钮启动和停止连续运行的后台工作程序,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,假设我有这样一个背景工人: private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { while(true) { //Kill zombies } } private void startButton_Click(System.Object sender,

假设我有这样一个背景工人:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
             while(true)
             {
                  //Kill zombies
             }
        }
private void startButton_Click(System.Object sender, 
    System.EventArgs e)
{
    // Start the asynchronous operation.
    backgroundWorker1.RunWorkerAsync();
}
private void cancelAsyncButton_Click(System.Object sender, 
    System.EventArgs e)
{   
    // Cancel the asynchronous operation.
    this.backgroundWorker1.CancelAsync();
}
   private void KillZombies(BackgroundWorker worker, DoWorkEventArgs e)
   {
        while (true)
        {
            if (worker.CancellationPending)
           {   
              e.Cancel = true;
           }
        }
   }

我怎样才能让这个后台工作人员开始和停止使用WinForm上的按钮?

我还没有测试过这个,我有一些代码,我必须要看清楚我到底做了什么,但这是Fredrik答案的改编:

private bool _performKilling;
private object _lockObject = new object();

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
     while(true)
     {

         if (_performKilling)
         {
             //Kill zombies
         }
         else
         { //We pause until we are woken up so as not to consume cycles
             Monitor.Wait(_lockObject);
         }
     }
}

private void StartKilling()
{
    _performKilling = true;
    Monitor.Pulse(_lockObject);
}

private void StopAllThatKilling()
{
    _performKilling = false;
]
此模式的更完整示例如下:


也许你可以使用像这样的手动重置事件,我没有调试它,但值得一试。如果它起作用,你就不会让线在等待的时候转动轮子

ManualResetEvent run = new ManualResetEvent(true);

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
     while(run.WaitOne()) 
     { 
         //Kill zombies 
     } 
} 

private void War() 
{ 
    run.Set();
} 

private void Peace() 
{ 
    run.Reset();
}
使用该方法

在工作线程内的循环中

if (backgroundWorker.CancellationPending) return;

这种情况不会立即发生。

停止是指停止还是暂停? 如果你的意思是停止,那么这是小菜一碟。为要负责启动后台工作程序的按钮创建一个按钮单击事件处理程序,并为负责停止后台工作程序的按钮创建一个按钮单击事件处理程序。在开始按钮上,调用触发do_work事件的后台工作程序方法。大概是这样的:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
             while(true)
             {
                  //Kill zombies
             }
        }
private void startButton_Click(System.Object sender, 
    System.EventArgs e)
{
    // Start the asynchronous operation.
    backgroundWorker1.RunWorkerAsync();
}
private void cancelAsyncButton_Click(System.Object sender, 
    System.EventArgs e)
{   
    // Cancel the asynchronous operation.
    this.backgroundWorker1.CancelAsync();
}
   private void KillZombies(BackgroundWorker worker, DoWorkEventArgs e)
   {
        while (true)
        {
            if (worker.CancellationPending)
           {   
              e.Cancel = true;
           }
        }
   }
在停止按钮上,调用将后台工作人员的
CancellationPending
设置为true的方法,如下所示:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
             while(true)
             {
                  //Kill zombies
             }
        }
private void startButton_Click(System.Object sender, 
    System.EventArgs e)
{
    // Start the asynchronous operation.
    backgroundWorker1.RunWorkerAsync();
}
private void cancelAsyncButton_Click(System.Object sender, 
    System.EventArgs e)
{   
    // Cancel the asynchronous operation.
    this.backgroundWorker1.CancelAsync();
}
   private void KillZombies(BackgroundWorker worker, DoWorkEventArgs e)
   {
        while (true)
        {
            if (worker.CancellationPending)
           {   
              e.Cancel = true;
           }
        }
   }
现在别忘了检查后台工作人员的doWork中是否有
CancelationPending
标志。大概是这样的:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
             while(true)
             {
                  //Kill zombies
             }
        }
private void startButton_Click(System.Object sender, 
    System.EventArgs e)
{
    // Start the asynchronous operation.
    backgroundWorker1.RunWorkerAsync();
}
private void cancelAsyncButton_Click(System.Object sender, 
    System.EventArgs e)
{   
    // Cancel the asynchronous operation.
    this.backgroundWorker1.CancelAsync();
}
   private void KillZombies(BackgroundWorker worker, DoWorkEventArgs e)
   {
        while (true)
        {
            if (worker.CancellationPending)
           {   
              e.Cancel = true;
           }
        }
   }
还有你的嫁妆方法:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
             BackgroundWorker worker = sender as BackgroundWorker;
             KillZombies(worker, e);
        }
我希望这能把你引向正确的方向。进一步阅读:


啊,当然了;很好的解决方案。我一定很累了,从一开始我就没想到;)“我没有对此进行测试”--很明显,因为对
Wait()
Pulse()
的调用将引发异常,因为您在调用这些方法之前没有使用监视器。@PeterDuniho当然这里没有显示一些管道。只是想让我们在监视器上使用两种方法来促进暂停/取消暂停。这里有一个更完整的例子:“访问和更新bool是一个原子操作”。这是因为内存障碍吗?不,原子意味着值true或false将一次性写入。内存障碍指示另一个线程看到值的写入或读取顺序。没有任何东西表明,如果没有这种机制,写入_performKilling的值在另一个线程中是可见的。原子性意味着读取的值总是true或false,这并不意味着后台线程会看到最近写入的值。它们是原子的,但为了安全起见,我可能会将其标记为volatile。这个紧环也不需要呼吸。它一直在以最快的速度构建数据,例如,我不会发布任何来自此循环的无效调用。一定要将标志标记为volatile,否则您可能会看到Heisenbug。是的,我应该澄清,通过线程安全,我指的是值将“一次性”写入和读取的事实。标记标志
volatile
可能会稍微提高访问顺序(但不是完全),因此为了在访问顺序和数据新鲜度方面真正安全起见,可能应该引入某种锁定机制(我将用它更新答案)(+1很高兴看到另一个真正理解.NET线程的灵魂。)我认为在这些情况下使用WaitHandle总是更好的选择,因为它们本质上为您解决了原子性和其他多线程问题(假设您选择了正确的WaitHandle类型)。
while(true){if(run.WaitOne()){}
?看起来有点多余,不是吗?为什么不
while(run.WaitOne()){}
?确实如此,我想我自己在发布后会更新它+1:我不明白为什么每个人都说要检查
,而(_someCustomBoolean)
BackgroundWorker
类已经内置了这个功能。一旦设置了取消挂起,我认为一般的协议是让后台工作人员停止并完成。在这种情况下,我相信这些问题是在寻找一种开始和结束的方式。背景工作人员也会让你绊倒。如果您使用它的oncompleted事件,这将通过.net通用线程池发布,我以前见过这个死锁,这取决于在那里抛出的其他内容。嗯,对于您接受的答案,请注意-您担心的是一个只会导致它不停止一两次迭代的效果,但是忘了你将要忙于整个处理器的旋转!至少在那里睡一觉。它看起来会起作用,但会造成很大的损害。其他一些答案解决了所有这些问题,就像你“应该”解决的那样。