我是VB.NET线程的新手
至于简单测试,我尝试了以下操作,我需要使用值平滑地填充列表框。 但它没有像我预期的那样工作,它挂起了界面。请让我知道我在这里做错了什么。
谢谢。
Imports System.Threading
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Thr As Threading.Thread
Thr = New Threading.Thread(New Threading.ThreadStart(AddressOf tprocess))
'Thr.SetApartmentState(ApartmentState.STA)
Thr.IsBackground = True
Thr.Start()
End Sub
Private Delegate Sub DoStuffDelegate()
Private Sub tprocess()
Dim i As Integer
For i = 0 To 20000
If Me.InvokeRequired Then
Me.Invoke(New DoStuffDelegate(AddressOf tprocess))
Else
ListBox1.Items.Add(i)
End If
Next
End Sub
End Class
答案 0 :(得分:1)
当您编写代码来创建线程时,您总是要担心线程可能导致的错误类型。它们非常难以诊断,解决它们的唯一方法就是知道它们存在并仔细编写代码,以便知道如何避免它们。
最常见的线程错误是线程争用,死锁和firehose错误。您的代码中有第1个和第3个错误。你在抱怨第三个。很快:线程竞争错误正在使用Me.InvokeRequired。当Me.Invoke()语句执行时,您无法保证它仍然是 true 。当用户在线程仍在运行时关闭窗口时,这会出错。当您尝试解决此问题时,您将看到第二个错误的样子。但你还没到那里。
firehose错误是Me.Invoke()调用。非常快,工作线程的工作时间不到一微秒,你以很高的速度完成20000次。然而,另一个线程实际上必须完成添加项目UI线程的工作。这是不快,它不仅需要添加项目,还需要重新绘制控件。很多微秒。
当这种情况发生时,你的UI线程正在燃烧100%核心,试图跟上无情的调用请求率。尽可能努力地将项目添加到列表框中。有些东西必须给予,而它正在这样做,它没有照顾它必须做的低优先级的工作。绘画并响应用户输入。实际上,您的UI看起来完全冻结了。你不能再看到它了,并试图关闭窗口不起作用。 实际上已经死了,它很难发挥作用。
需要一段时间,可能是几秒钟,给予或接受。直到工作线程完成其for()循环并停止使用调用请求猛击UI线程。一切都恢复正常。
像这样的firehose bug是非常基础的。解决它的唯一方法是减少调用Invoke()或降低速率。注意如何在Invoke()调用之后立即修复Thread.Sleep(50)。但当然这会大大减慢你的工作线程。通过使用AddRange()而不是Add(),一次添加(比方说)1000个项目,可以减少调用Invoke()的频率。哪个是正确的修复,但现在仍然尝试从工作线程更新列表框变得毫无意义。也可以通过单 AddRange()调用来完成。最快捷的方式。答案 1 :(得分:0)
尝试更改:
Thr = New Threading.Thread(New Threading.ThreadStart(AddressOf tprocess))
到此:
Thr = New Threading.Thread(AddressOf tprocess)
ThreadStart将立即启动该线程
答案 2 :(得分:0)
我尝试了以下方式。我几乎很容易处理。 Backgroudworker完美地处理了这种情况。
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object,ByVal e As System.ComponentModel.DoWorkEventArgs)处理BackgroundWorker1.DoWork
Dim i As Integer
For i = 1 To 20000
BackgroundWorker1.ReportProgress((i / 20000) * 100, i)
Threading.Thread.Sleep(1)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
ListBox1.Items.Add(e.UserState)
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
MsgBox("Complete")
End Sub