0

我正在尝试创建一个多线程程序来轮询机器以获取数据,但我似乎无法让它正常工作。下面的代码正在运行,并且正在创建 4 个线程,但代码流似乎是串行发生的,并且在主 UI 线程上发生。

我想要实现的是数据网格的每一行同时更新而不锁定 UI。

下面是我所拥有的内容的简化版本,但它可以证明问题。对于信息,“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
4

2 回答 2

1

运行你的代码有点不同,这就是 vb.net 中多线程的结构应该是什么样的(它与 Vb.net 没有将命名空间传递给我理解的模型有关)

这将是您从 MainThread 加载的 startThread 或 w/e 有您

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

于 2013-07-25T20:52:16.837 回答
-1

您可以将计时器和后台工作者与 DoWorkEventHandler 和 RunWorkerCompletedEventHandler 的事件一起使用。

示例: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.
    }
于 2013-07-15T12:36:16.267 回答