为什么我的委托从backgroundworker调用在主线程中运行

时间:2014-10-30 16:49:32

标签: vb.net multithreading backgroundworker system.timers.timer

我正在编写一个程序,允许我运行许多不同的硬件测试程序。

例程可能非常耗时,持续时间长达30分钟。在此期间,我必须控制一系列测试设备来设置条件并进行测量。

我当时认为使用后台工作人员执行任务将是理想的,并允许UI保持响应。这很有效,直到其中一个例程要求我每1.5秒进行一次测量。我正在使用系统计时器来触发这些事件。计时器是在后台工作程序的doWork子程序中创建和启动的,但是,我发现委托在主(UI)线程中运行,而不是像我想的那样在后台工作程序线程中运行。

我做错了吗?我附上了具有相同结构的简化程序的主要部分。

  Private Sub getMeasurement()
    ' Runs in backgroundWorker thread
    Me.TextBox2.Text = (System.DateTime.Now - startTime).TotalSeconds.ToString
    startTime = System.DateTime.Now
    Debug.Print("Thread name is " & Thread.CurrentThread.Name & ", ID = " & Thread.CurrentThread.ManagedThreadId)
End Sub

 Private Sub OnTimedEvent()
    'Runs in own thread, Calls getMeasurement which runs in BackgroundWorker thread
    Thread.CurrentThread.Name = "OTE"
    Debug.Print("In OnTimedEvent, thread = " & Thread.CurrentThread.Name & ", ID = " & Thread.CurrentThread.ManagedThreadId)
    Dim ServiceTimerDelegate As New ServiceTimerDelegate(AddressOf getMeasurement)
    Me.BeginInvoke(ServiceTimerDelegate)
End Sub

  Private Sub backgroundWorker1_DoWork(ByVal sender As System.Object, _
ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork

    Thread.CurrentThread.Name = "BW1"
    mTimer = New Timers.Timer(1490) ' 14.9secs (allow for some latency)
    AddHandler mTimer.Elapsed, New Timers.ElapsedEventHandler(AddressOf OnTimedEvent)
    Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
    Dim i As Integer

    'main timer for measurements every 1.5secs (may change to take interval from UI)
    Select Case e.Argument
        Case "Sunday"

            mTimer.Start()
            Debug.Print("Thread in DoWork = " & Thread.CurrentThread.Name & ", ID = " & Thread.CurrentThread.ManagedThreadId)

            startTime = System.DateTime.Now

            'main loop for temperature ramping
            For i = 20 To 70
                If (worker.CancellationPending = True) Then
                    e.Cancel = True
                Else
                    Thread.Sleep(500)
                    worker.ReportProgress((i - 19) * (100 / 50))
                    i += 1

                End If

            Next
        Case Else
            e.Cancel = True
    End Select
End Sub

1 个答案:

答案 0 :(得分:0)

这里有三件事令人困惑,让我觉得你上面发布的代码并没有真正使用BackgroundWorker来实现它的功能。

  1. DoWork事件始终在与UI不同的线程中运行。这就是它的全部要点。 ReportProgress在UI线程中运行,但您没有使用它。

  2. 在上面的代码中,您实际上似乎根本没有运行BackgroundWorker。相反,你似乎正在使用ServiceTimerDelegate - 不是100%确定我知道那是什么。您已经在DoWork处理程序中定义了BackgroundWorker(这没有任何意义),但您似乎从未将BackgroundWorker挂钩到该处理程序,也不会在其上调用RunWorkerAsync。

  3. 即使您在BackgroundWorker中运行getMeasurement(),它也会失败 - 您正在改变UI项目的内容,这会因InvalidCrossThreadAccess而导致异常。如果需要更改UI控件,请使用在UI线程中发生的ReportProgress事件。