Member 11112814 Ответов: 3

Vb2017: что и зачем вызывать и делегировать?


Всем привет,

В приведенном ниже коде я изучаю многопоточность.
Код работает нормально но только благодаря субмарине:

Частная суб методе form1_load (как byval отправителя как системы.Объект, asSystem бывал.EventArgs) Обрабатывает MyBase.Load
Меня.CheckForIllegalCrossThreadCalls = Ложь
Конец Подводной Лодки

Без этой субмарины я получаю сообщения об ошибках.
Я понимаю, что это происходит потому, что я даю потоку внешние команды, а именно: Label1.Text = Number1 или что-то в этом роде.

Я знаю, что теперь мне следует использовать invoke и delegate, но я не знаю, где именно в этом коде, потому что я не очень хорошо понимаю invoke и delegate..

Может быть, кто-то может помочь мне дальше?

Спасибо,

Эрик



Public Class Form1

    Dim Number1 As Integer
    Dim Number2 As Integer
    Dim Thread1 As System.Threading.Thread
    Dim Thread2 As System.Threading.Thread

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.CheckForIllegalCrossThreadCalls = False
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Thread1 = New System.Threading.Thread(AddressOf Telop)
        Thread1.Start()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Thread2 = New System.Threading.Thread(AddressOf Telaf)
        Thread2.Start()
    End Sub

    Private Sub Telop()
        Do Until Number1 = 10000
            Number1 = Number1 + 1
            Label1.Text = Number1
            'Me.Refresh()
        Loop
    End Sub 'Telop

    Private Sub Telaf()
        Number2 = 10000
        Do Until Number2 = 0
            Number2 = Number2 - 1
            Label2.Text = Number2
            'Me.Refresh()
        Loop
    End Sub 'Telaf

End Class


Что я уже пробовал:

vb2017: что и зачем вызывать и делегировать?

3 Ответов

Рейтинг:
20

Dave Kreskowiak

Делегаты-это то, что другие языки свободно называют "указателями функций".

Поскольку вы не можете коснуться элемента управления из другого потока, вы должны использовать Sub или функцию, чтобы обновить элемент управления так, как вы хотите. Теперь вы должны каким-то образом вызвать этот метод, но вы должны сделать это таким образом, чтобы сказать: "я хочу, чтобы этот поток вызвал этот метод." Вот тут-то и приходит призыв.

В вашем примере у вас может быть Sub, который задает свойство Text определенного элемента управления label:

Private Delegate Sub UpdateLabel1Delegate(ByVal message As String)

Private Sub UpdateLabel1Text(ByVal message As String)
    If Label1.InvokeRequired Then
        ' This is a cross-thread call, so
        ' invoke a call back to this method.
        Me.BeginInvoke(New UpdateLabel1Delegate(AddressOf UpdateLabel1Text), message)
    Else
        ' We're being called on the UI thread, so just update the label.
        Label1.Text = message
    End If
End Sub

.
.
.

   ' Code running on a non-UI thread...
   UpdateLabel1Text("This is a test...")


Рейтинг:
1

Ralf Meier

Сначала я предлагаю вам прочитать что-нибудь еще об этих вещах ...

Тогда - к вашему вопросу :
Вы объявили свои 2 потока.
С помощью нажатия кнопки вы делегируете метод одному из этих потоков. Теперь он будет исполнен.
Внутри вашего метода потока вы пытаетесь получить доступ к элементу из основного потока (Label2). Это невозможно, поскольку элемент может принадлежать только одному владельцу - в данном случае основному потоку.
Таким образом, вы должны построить Invoke-метод, который позволяет элементу управления выполнять свою работу, когда он в состоянии это сделать.

Но когда вы измените свой код, чтобы он работал правильно (вызывая), вы не увидите увеличивающегося значения внутри метки, потому что ваш поток выполняет свою работу за миллисекунды. Вы должны войти в поток.Спите внутри своего метода ...


Рейтинг:
0

OriginalGriff

Перекрестные вызовы потоков - это когда вы запускаете новый поток и он пытается получить доступ к любому элементу пользовательского интерфейса - потому что они "принадлежат" исходному потоку - потоку пользовательского интерфейса-и все начинает идти довольно грушевидно, если один и тот же элемент управления доступен из нескольких потоков, точно так же, как у вас есть один водитель в автомобиле: больше людей, пытающихся управлять одновременно, не помогут!

Setting CheckForIllegalCrossThreadCalls to False means that the system doesn't raise an exception when you do try from the wrong thread. That's not a good thing: it doesn't fix potential problems it just makes your code not know about them - a bit like the driver not being told that his mate in the back seat also has a steering wheel. The car still doesn't work properly, but now the driver doesn't know why because he hasn't been told. Worse, until your app crashes as a result, you won't necessarily know that your data is corrupt and that can cause some real problems (imagine if your bank didn't know it took money from your account instead of mine).

Вызов кажется сложным, но это не так, не совсем так. Все, что вам нужно сделать, это проверить, какой поток вы используете. Контроль.Свойство Свойство Invokerequired [^] и если он установлен, вы используете Invoke для запуска метода в исходном потоке: Практическое руководство практическое руководство.[^]