0

我正在编写一个程序,它允许我运行多个不同的硬件测试例程。为什么我的代理从backgroundworker调用在主线程中运行

这些例程可能相当耗时,持续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

是什么让你说DoWork事件正在UI线程中运行? – furkle 2014-10-30 16:51:11

+1

如果'getMeasurement()'在一个线程中运行,那么这行:'Me.TextBox2.Text =(System.DateTime.Now - startTime).TotalSeconds.ToString'应该失败,因为您试图更新UI中的一个不是UI线程的线程。你有没有'CheckForIllegalCrossThreadCalls'被禁用了吗? – 2014-10-30 17:02:25

+1

这完全正常,您使用表单的BeginInvoke()方法运行getMeasurement()。 *是必需的*,您不能从工作线程更新UI。 System.Timers.Timer没有任何用处,你可以使用winforms定时器。对于BackgroundWorker来说,它几乎是一样的,除了睡觉之外什么都不做。 – 2014-10-30 17:16:34

回答

0

三两件事混淆了这里,使我觉得你上面贴的代码没有实际使用的BackgroundWorker其功能。

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

  2. 在上面的代码中,你实际上并没有运行BackgroundWorker。相反,你似乎在使用ServiceTimerDelegate--并非100%确定我知道那是什么。你已经在你的DoWork处理程序中定义了一个BackgroundWorker(这是毫无意义的),但是你似乎实际上并没有将BackgroundWorker挂钩到该处理程序,也没有在其上调用RunWorkerAsync。

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

+0

这不是一个答案。 – 2014-10-30 16:55:44

+0

@roryap“你没有在BackgroundWorker中运行你的代码”不是为什么代码没有按照他预期的方式在BackgroundWorker中执行的答案吗?我的意思是,如果我对这个事实错误,是的,这是一个糟糕的答案,但这似乎是他混乱的一个重要部分。 – furkle 2014-10-30 16:56:22

+0

我想你是对的。 – 2014-10-30 16:59:56

相关问题