2013-10-11 20 views
1

我有一些困難處理停止,然後啓動後臺工作人員使用VB.net時,只有一個非常小的時間間隔CancelAsync()調用和RunWorkerAsync( )電話。我已經創建了一個例子來說明下面的問題。如果單擊按鈕一次,然後快速連續單擊兩次,則會出現此示例中的問題。實質上,據我所知,問題在於後臺工作者仍在循環遍歷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 

編輯:

用羅斯壓的建議,我提高了示例代碼。雖然解決方案似乎有點不好。

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 
+0

如果BackgroundWorker的當前運行然後取消被擊中時禁用按鈕。在RunWorkerCompleted()事件中重新啓用它。 –

+0

@空閒心感謝您的評論。我相信這會比解決方案更具解決方法,但我認爲我可以暫時處理這個問題。 – Sepia

+0

您正試圖「按住」按鈕點擊處理程序中的代碼,直到發生其他一些事件。這是一個禁止...... –

回答

3

如何對這種做法......我們只是用一個新的替換舊的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 
+0

謝謝你。這是一個很好的答案,它很好地解決了這個問題。 – Sepia

1

而不是檢查IsBusy的,我會處理BackgroundWorker.RunWorkerCompletedevent

當後臺操作完成時,已被取消,或已產生的異常。

並推遲重新啓動worker到您的處理程序的事件。

+0

感謝您的迴應。不過,我認爲這不能解決問題。後臺進程不一定需要立即重新啓動,只是它有可能立即重新啓動(如果這是用戶選擇的)。 – Sepia

+1

(編輯窗口錯過了。) 也就是說,如果用戶需要,程序必須重新啓動後臺工作程序,在此示例中通過按鈕單擊表示。 – Sepia