2013-07-15 95 views
0

我想创建一个多线程程序来轮询数据的机器,但我似乎无法让它正常工作。下面的代码正在工作,正在创建4个线程,但是代码的流程似乎是在系列和主UI线程中发生的。Vb.net多线程不工作...?

我想要实现的是为datagrid的每一行更新,而不锁定用户界面。

下面是我所拥有的一个虚拟版本,但它用来演示问题。 有关信息,'testclass'是一个用作机器实例的类,每个类元素代表一台机器的属性。

希望我已经提供了足够的信息来解释问题。提前致谢。

Ps我应该不需要刷新窗体吗?

Imports System.Threading 

Public Class TestForm 

Public threadcount As Integer 
Public Delegate Sub testclassDelegate(test As Object) 

Private Class testclass 
    Public index As Integer 
    Public TestVal1 As Integer = 100 
    Public TestVal2 As Integer = 200 
    Public TestVal3 As Integer = 300 
    Public TestVal4 As Integer = 400 
    Public TestVal5 As Integer = 500 
    Public TestVal6 As Integer = 600 
    Public testDel As testclassDelegate 
End Class 

Private Sub TestForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    For i As Integer = 0 To 3 
     DataGridView1.Rows.Add() 
     DataGridView1.Rows(i).Cells(0).Value = i + 1 
    Next 
End Sub 

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    For i As Integer = 0 To 3 
     DataGridView1.Rows(i).Cells(1).Value = "" 
     DataGridView1.Rows(i).Cells(2).Value = "" 
     DataGridView1.Rows(i).Cells(3).Value = "" 
     DataGridView1.Rows(i).Cells(4).Value = "" 
     DataGridView1.Rows(i).Cells(5).Value = "" 
     DataGridView1.Rows(i).Cells(6).Value = "" 
    Next 
    Poll_FreeThread() 
End Sub 

Private Sub Poll_FreeThread() 
    For i As Integer = 0 To DataGridView1.Rows.Count - 1 
     Dim test As New testclass 
     test.index = i 
     test.testDel = AddressOf UIUpdate 

     Interlocked.Increment(threadcount) 
     Me.Label2.Text = threadcount 
     Try 
      Dim thPoll As New Thread(Sub() invokeUIUpdate(test)) 
      thPoll.IsBackground = True 
      thPoll.Priority = ThreadPriority.BelowNormal 
      thPoll.Start() 
     Catch ex As Exception 
      MsgBox(ex.Message) 
     End Try 
    Next 
End Sub 

Public Sub invokeUIUpdate(test As Object) 
    If DataGridView1.InvokeRequired Then 
     DataGridView1.Invoke(New testclassDelegate(AddressOf UIUpdate), test) 
    Else 
     UIUpdate(test) 
    End If 
End Sub 

Public Sub UIUpdate(test As Object) 
    Thread.Sleep(test.index * 100) 
    DataGridView1.Rows(test.index).Cells(1).Value = test.TestVal1 
    Me.Refresh() 
    Thread.Sleep(100) 
    DataGridView1.Rows(test.index).Cells(2).Value = test.TestVal2 
    Me.Refresh() 
    Thread.Sleep(100) 
    DataGridView1.Rows(test.index).Cells(3).Value = test.TestVal3 
    Me.Refresh() 
    Thread.Sleep(100) 
    DataGridView1.Rows(test.index).Cells(4).Value = test.TestVal4 
    Me.Refresh() 
    Thread.Sleep(100) 
    DataGridView1.Rows(test.index).Cells(5).Value = test.TestVal5 
    Me.Refresh() 
    Thread.Sleep(100) 
    DataGridView1.Rows(test.index).Cells(6).Value = test.TestVal6 
    Me.Refresh() 
    Interlocked.Decrement(threadcount) 
    Me.Label2.Text = threadcount 
End Sub 

End Class 
+0

提示:设置一个'invokeUIUpdate'上的断点,看看'if'会发生什么。 –

+0

1.您是否使用_Me.InvokeRequired_而不是_DataGridView1.InvokeRequired_来检查? 2.另外,在设置每个单元格值之后,不需要调用_Me.Refresh()_,您可以在设置最后一个单元格值后将其放置一次。 – Coder

+0

谢谢雷蒙德。这已经超出了我的想法,但唉,它不是运行其他条件,如果这就是你的意思? – doovers

回答

1

运行代码有点不同,这是结构应该是什么样子像多线程在vb.net(它是与Vb.net不及格命名空间为模型,从我的理解)

这将是你从MainThread负载或W/E startThread有你

Private Sub DoSomethingSimple() 
    Dim DoSomethingSimple_Thread As New Thread(AddressOf DoSimple) 
    DoSomethingSimple_Thread.Priority = ThreadPriority.AboveNormal 
    DoSomethingSimple_Thread.Start(Me) 
End Sub 

这将是实际的线程本身(新型号/班,或在同一类)

Private Sub DoSimple(beginform As Form) 
    'Do whatever you are doing that has nothing to do with ui 

    'For UI calls use the following 
    SomethingInvoked(PassibleVariable, beginform) 

End Sub 

撰写代表和调用方法每次调用主线程。

Delegate Sub SomethingInvoked_Delegate(s As Integer, beginform As Form) 
Sub SomethingInvoked_Invoke(ByVal s As Integer, beginform As Form) 
    If beginform.NameOfControlYouAreUpdating.InvokeRequired Then ' change NameOfControlYouAreUpdating to the Name of Control on the form you wish to update 
     Dim d As New SomethingInvoked_Delegate(AddressOf SomethingInvoked_Invoke) 
     beginform.Invoke(d, New Object() {s, beginform}) 
    Else 

     'Do something... 
     beginform.NameOfControlYouAreUpdating.Condition = Parameter 

    End If 
End Sub 

这是测试(非挂)在vb.net

写线程的方式。如果您需要进一步帮助实现你的代码,这个模板让我知道:P

+0

感谢您的代码修改工作! – doovers

-1

您可以使用带有DoWorkEventHandler和RunWorkerCompletedEventHandler事件的timer和backgroundworker。

例如:C#示例:

private void Button1_Click(object sender, EventArgs e) 
{ 
workerThreadForLetters.WorkerReportsProgress = true;     workerThreadForLetters.WorkerSupportsCancellation = true; 
workerThreadForLetters.DoWork -= new DoWorkEventHandler(workerThreadForLetters_DoWork); 
workerThreadForLetters.DoWork += new DoWorkEventHandler(workerThreadForLetters_DoWork); 

workerThreadForLetters.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(workerThreadForLetters_RunWorkerCompleted); 

workerThreadForLetters.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThreadForLetters_RunWorkerCompleted); 
} 
    private void workerThreadForLetters_DoWork(object sender, DoWorkEventArgs e) 
    { 
       //DO SOMETHING 
    } 
    private void workerThreadForLetters_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
      //DO AS REQUIRED 
      Timer1.enable = false; 
    } 
    private void tmCollectionLettersUpdate_Tick(object sender, EventArgs e) 
    { 
      //Content update like % of data progressed or any. 
    } 
+0

谢谢你的建议和原谅我的无知,但我不仅限于一名后台工作者?最终我将连续循环轮询多达100台机器,所以我不确定bgworker是否能在这种情况下工作? – doovers

+0

您可以根据需要启动尽可能多的背景工作者 - 但这不是一个好的解决方案。我认为一个线程池可能更适合。这是理论知识,所以我不提供代码 - 对不起。但是,您应该考虑只使用少量线程,具体取决于线程的资源消耗。 –

+0

嗨基督教。实际上,我在我的解决方案中编写了两个选项,一个使用线程池,另一个使用无限的线程,稍后用多台机器进行测试,看看我能推多远。我的问题是,当轮询机器时需要快速周转,但程序将在专用机器上连续运行,所以我认为可以推送它,因为不会有该机器的任何其他要求。这对我来说是全新的领域,但我愿意接受任何建议! – doovers