【问题标题】:Stopping and then starting the same background worker in quick succession快速连续停止然后启动同一个后台工作程序
【发布时间】:2013-10-12 12:55:56
【问题描述】:

当 CancelAsync() 调用和 RunWorkerAsync() 调用之间只有非常小的间隔时,我在处理使用 VB.net 停止然后启动后台工作程序时遇到了一些困难。我创建了一个示例来说明以下问题。如果单击一次按钮然后快速连续单击两次,则会出现此示例中的问题。本质上,据我了解,问题在于后台工作人员仍在迭代 for 循环(包括模仿需要一些时间运行的代码),并且还没有机会检查取消是否处于待处理状态。

我尝试使用的解决方案是等待后台工作人员关闭,然后再次启动工作人员。但是,这个 while 循环会无限迭代——后台工作人员永远不会终止。我假设让主线程进入睡眠状态也会让后台工作线程进入睡眠状态。这是正确的吗?

问题:当检查挂起的取消不能比现在更频繁地合理地进行时,停止后台工作程序然后可能需要在几分之一秒后重新启动它的推荐方法是什么?

非常感谢您的建议和建议。

Public Class Form1
    Dim WithEvents bgWorker As System.ComponentModel.BackgroundWorker = New System.ComponentModel.BackgroundWorker
    Friend WithEvents startStopButton As Button = New Button
    Dim workerShouldBeRunning As Boolean = False
    Sub startStopButton_click() Handles startStopButton.Click
        If workerShouldBeRunning Then
            bgWorker.CancelAsync()
        Else
            While bgWorker.IsBusy
                Threading.Thread.Sleep(1)
            End While
            bgWorker.RunWorkerAsync()
        End If
        workerShouldBeRunning = Not workerShouldBeRunning
    End Sub
    Sub bgWorker_doWork() Handles bgWorker.DoWork
        While Not bgWorker.CancellationPending
            Dim sum As Long
            For counter = 1 To 100000
                sum += counter
            Next

            Threading.Thread.Sleep(1000)
        End While

    End Sub

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        startStopButton.Location = New Point(10, 100)
        startStopButton.Size = New System.Drawing.Size(200, 23)
        startStopButton.Text = "Click" 'Click to start or stop the background dummy process.
        Me.Controls.Add(startStopButton)
        bgWorker.WorkerSupportsCancellation = True
    End Sub
End Class

编辑:

根据 Ross Presser 的建议,我改进了示例代码。不过,这个解决方案似乎有点糟糕。

Public Class Form1
    Dim WithEvents bgWorker As System.ComponentModel.BackgroundWorker = New System.ComponentModel.BackgroundWorker
    Friend WithEvents startStopButton As Button = New Button
    Dim workerShouldBeRunning As Boolean = False
    Dim startQueued As Boolean = False
    Sub startStopButton_click() Handles startStopButton.Click
        If workerShouldBeRunning Then
            bgWorker.CancelAsync()
        Else
            If bgWorker.IsBusy Then
                startQueued = True
            Else
                bgWorker.RunWorkerAsync()
            End If
        End If
        workerShouldBeRunning = Not workerShouldBeRunning
    End Sub
    Sub bgWorker_doWork() Handles bgWorker.DoWork
        While Not bgWorker.CancellationPending
            Dim sum As Long
            For counter = 1 To 100000
                sum += counter
            Next

            Threading.Thread.Sleep(1000)
        End While

    End Sub
    Sub bgWorkerCompleted() Handles bgWorker.RunWorkerCompleted
        If startQueued Then
            startQueued = False
            bgWorker.RunWorkerAsync()
        End If
    End Sub



    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        startStopButton.Location = New Point(10, 100)
        startStopButton.Size = New System.Drawing.Size(200, 23)
        startStopButton.Text = "Click" 'Click to start or stop the background dummy process.
        Me.Controls.Add(startStopButton)
        bgWorker.WorkerSupportsCancellation = True
    End Sub
End Class

【问题讨论】:

  • 如果 BackgroundWorker 当前正在运行,则在点击取消时禁用该按钮。在 RunWorkerCompleted() 事件中重新启用它。
  • @idle-mind 感谢您的评论。我相信这更像是一种解决方法而不是修复方法,但我认为我暂时可以解决这个问题。
  • 您试图在按钮单击处理程序中“保留”代码,直到发生其他事件。这是一个禁忌......
  • @idle-mind 我同意我试图使用比你更糟糕的解决方法。禁用按钮虽然可能会让用户感到困惑,但效果要好得多。

标签: vb.net backgroundworker background-process


【解决方案1】:

这种方法怎么样?...我们只需将旧的 backgroundworker 替换为新的:

Public Class Form1

    Private WithEvents startStopButton As Button = New Button
    Private WithEvents bgWorker As System.ComponentModel.BackgroundWorker = Nothing

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        startStopButton.Location = New Point(10, 100)
        startStopButton.Size = New System.Drawing.Size(200, 23)
        startStopButton.Text = "Click" 'Click to start or stop the background dummy process.
        Me.Controls.Add(startStopButton)
    End Sub

    Private Sub startStopButton_click() Handles startStopButton.Click
        If IsNothing(bgWorker) Then
            Static bgwCounter As Integer = 0
            bgwCounter = bgwCounter + 1
            bgWorker = New System.ComponentModel.BackgroundWorker
            bgWorker.WorkerSupportsCancellation = True
            bgWorker.RunWorkerAsync(bgwCounter)
        Else
            bgWorker.CancelAsync()
            bgWorker = Nothing
        End If
    End Sub

    Private Sub bgWorker_doWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork
        Dim bgwCounter As Integer = e.Argument
        Debug.Print("Running #" & bgwCounter)
        Dim bgw As System.ComponentModel.BackgroundWorker = sender
        While Not bgw.CancellationPending
            Dim sum As Long
            For counter As Integer = 1 To 100000
                sum += counter
            Next

            Threading.Thread.Sleep(1000)
        End While
        Debug.Print("Cancelled #" & bgwCounter)
    End Sub

End Class

【讨论】:

  • 谢谢。这是一个很好的答案,它很好地解决了问题。
【解决方案2】:

我不会检查IsBusy,而是处理BackgroundWorker.RunWorkerCompletedevent

在后台操作完成、取消或引发异常时发生。

并将重新启动工作人员推迟到此事件的处理程序。

【讨论】:

  • 感谢您的回复。但是,我认为这并不能解决问题。后台进程不一定需要立即重新启动,只是它有可能立即重新启动(如果这是用户选择的话)。
  • (编辑窗口丢失。)也就是说,程序必须仅在用户想要的情况下重新启动后台工作程序,在此示例中由按钮单击表示。
猜你喜欢
  • 2023-03-17
  • 1970-01-01
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 2011-07-10
相关资源
最近更新 更多