Vb.net 快速连续停止然后启动同一后台工作程序

Vb.net 快速连续停止然后启动同一后台工作程序,vb.net,backgroundworker,background-process,Vb.net,Backgroundworker,Background Process,在CancelAsync()调用和RunWorkerAsync()调用之间只有很小的间隔时,我很难使用VB.net停止然后启动后台工作程序。我创建了一个示例来说明下面的问题。如果快速连续单击按钮一次,然后单击两次,则会出现此示例中的问题。基本上,据我所知,问题在于后台工作程序仍在迭代for循环(包括模拟运行需要一些时间的代码),并且还没有机会检查取消是否挂起 我尝试使用的解决方案是等待后台工作程序关闭,然后再次启动该工作程序。然而,这个while循环无限期地迭代——后台工作进程永远不会终止。我假

在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

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


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

我将处理
BackgroundWorker.RunWorkerCompleted
而不是检查
IsBusy

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


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

这种方法如何?…我们只需将旧的backgroundworker替换为新的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

这种方法怎么样?…我们只是用新的backgroundworker替换旧的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

谢谢你的回复。然而,我认为这并不能解决问题。后台进程不一定需要立即重新启动,只是它有可能立即重新启动(如果这是用户选择的)。(编辑窗口丢失。)也就是说,如果用户需要,程序只需重新启动后台工作程序,在本例中,通过单击按钮表示。感谢您的回复。然而,我认为这并不能解决问题。后台进程不一定需要立即重新启动,只是它有可能立即重新启动(如果这是用户选择的)。(编辑窗口丢失。)也就是说,如果用户需要,程序只需重新启动后台工作程序,在本例中,单击按钮表示。如果BackgroundWorker当前正在运行,则在单击“取消”时禁用该按钮。在RunWorkerCompleted()事件中重新启用它。@idle mind感谢您的评论。我相信这更像是一种解决方法,而不是修复方法,但我认为我暂时可以解决这个问题。您正在尝试在按钮单击处理程序中“保留”代码,直到发生其他事件。这是一个不,不…@懒惰的想法我同意我试图使用比你更糟糕的解决方法。禁用按钮,虽然可能会让用户感到困惑,但要好得多。如果BackgroundWorker当前正在运行,则在单击“取消”时禁用按钮。在RunWorkerCompleted()事件中重新启用它。@idle mind感谢您的评论。我相信这更像是一种解决方法,而不是修复方法,但我认为我暂时可以解决这个问题。您正在尝试在按钮单击处理程序中“保留”代码,直到发生其他事件。这是一个不,不…@懒惰的想法我同意我试图使用比你更糟糕的解决方法。禁用按钮,虽然可能会让用户感到困惑,但要好得多。谢谢。这是一个很好的答案,它很好地解决了问题。谢谢。这是一个很好的答案,它很好地解决了问题。