Visual Basic .NET Language
Многопоточность
Поиск…
Выполнение потокобезопасных вызовов с помощью Control.Invoke ()
Используя метод Control.Invoke()
вы можете переместить выполнение метода или функции из фонового потока в поток, на который был создан элемент управления, который обычно является потоком пользовательского интерфейса (User Interface). Таким образом, ваш код будет помещен в очередь для запуска в потоке элемента управления, что устраняет возможность параллелизма.
Свойство Control.InvokeRequired
также должно быть проверено, чтобы определить, нужно ли вам вызывать, или если код уже работает в том же потоке, что и элемент управления.
Метод Invoke()
принимает делегат в качестве первого параметра. Делегат содержит ссылку, список параметров и тип возвращаемого значения для другого метода.
В Visual Basic 2010 (10.0) или выше лямбда-выражения могут использоваться для создания метода делегата «на лету»:
If LogTextBox.InvokeRequired = True Then
LogTextBox.Invoke(Sub() LogTextBox.AppendText("Check passed"))
Else
LogTextBox.AppendText("Check passed")
End If
Если в Visual Basic 2008 (9.0) или ниже, вы должны объявить делегата самостоятельно:
Delegate Sub AddLogText(ByVal Text As String)
If LogTextBox.InvokeRequired = True Then
LogTextBox.Invoke(New AddLogText(AddressOf UpdateLog), "Check passed")
Else
UpdateLog("Check passed")
End If
Sub UpdateLog(ByVal Text As String)
LogTextBox.AppendText(Text)
End Sub
Выполнение потокобезопасных вызовов с использованием Async / Await
Если мы попытаемся изменить объект в потоке пользовательского интерфейса из другого потока, мы получим исключение операции поперечного потока:
Private Sub Button_Click(sender As Object, e As EventArgs) Handles MyButton.Click
' Cross thread-operation exception as the assignment is executed on a different thread
' from the UI one:
Task.Run(Sub() MyButton.Text = Thread.CurrentThread.ManagedThreadId)
End Sub
Перед VB 14.0 и .NET 4.5 решение вызывало назначение и объект, живущий в потоке пользовательского интерфейса:
Private Sub Button_Click(sender As Object, e As EventArgs) Handles MyButton.Click
' This will run the conde on the UI thread:
MyButton.Invoke(Sub() MyButton.Text = Thread.CurrentThread.ManagedThreadId)
End Sub
С VB 14.0 мы можем запустить Task
в другом потоке, а затем восстановить контекст после завершения выполнения, а затем выполнить назначение с помощью Async / Await:
Private Async Sub Button_Click(sender As Object, e As EventArgs) Handles MyButton.Click
' This will run the code on a different thread then the context is restored
' so the assignment happens on the UI thread:
MyButton.Text = Await Task.Run(Function() Thread.CurrentThread.ManagedThreadId)
End Sub