Что делает этот BeginInvoke (Sub ())? - PullRequest
0 голосов
/ 23 апреля 2020

Я сталкиваюсь со следующим кодом:

    Public Sub fun_imageCallback(ByVal data As IntPtr, ByVal rows As Integer, ByVal cols As Integer, ByVal channels As Integer, ByVal timestamp As Long)


        'Console.WriteLine(rows + " " + cols + " " + channels);
        imageMutex.WaitOne()
        If imageCamera IsNot Nothing Then
            imageCamera.Dispose()
        End If

        imageCamera = New Bitmap(cols, rows, channels * cols, PixelFormat.Format8bppIndexed, data)

        ' The default palette has strange colours, not grayscale
        Dim pal As ColorPalette = imageCamera.Palette
        For i As Integer = 0 To 255
            pal.Entries(i) = Color.FromArgb(i, i, i)
        Next
        imageCamera.Palette = pal
        imageMutex.ReleaseMutex()

        If Me.InvokeRequired Then

            Me.BeginInvoke(
        Sub()
            imageMutex.WaitOne()

            pbCamera.Image = DirectCast(imageCamera.Clone(), Bitmap)
            imageMutex.ReleaseMutex()
        End Sub
    )
        End If

    End Sub

Я не понимаю, что делают следующие 4 строки:

    If Me.InvokeRequired Then

        Me.BeginInvoke(
    Sub()
        imageMutex.WaitOne()

Как это прочитать?

Спасибо!

1 Ответ

3 голосов
/ 23 апреля 2020

Я предлагаю вам сначала прочитать this для некоторого фона.

Смысл свойства InvokeRequired состоит в том, чтобы определить, выполняете ли вы в данный момент поток, которому принадлежит указанный контроль или нет. InvokeRequired равно False, когда вы получаете его в потоке, который создал элемент управления, и True в каждом другом потоке. Вообще говоря, все элементы управления создаются в одном потоке - в потоке, в котором было запущено приложение, - поэтому его часто называют потоком пользовательского интерфейса.

Если вы выполняете в потоке, создавшем элемент управления тогда безопасно получить доступ к другим членам этого контроля напрямую. Если вы находитесь в другом потоке, вам нужно вызвать вызов метода в потоке-владельце, иначе могут произойти плохие вещи. Методы Invoke и BeginInvoke выполняют вызов метода в потоке, создавшем элемент управления. Invoke ожидает завершения вызова, в то время как BeginInvoke немедленно возвращается, и код продолжает выполняться в текущем потоке, в то время как вызванный метод выполняется в потоке пользовательского интерфейса.

В вашем случае важной частью является следующее:

pbCamera.Image = DirectCast(imageCamera.Clone(), Bitmap)

То есть доступ к свойству Image PictureBox, так что это должно быть сделано в потоке пользовательского интерфейса. Код проверяет свойство InvokeRequired формы и, если это False, это означает, что текущий код НЕ выполняется в потоке пользовательского интерфейса, поэтому небезопасен прямой доступ к этому свойству Image. Метод BeginInvoke выполнит указанное лямбда-выражение в потоке пользовательского интерфейса, что обеспечит безопасный доступ к этому свойству Image в нем.

При вызове Invoke или BeginInvoke вы указываете метод Вы хотите выполнить, предоставив делегата. Делегат - это объект, который ссылается на метод. Делегаты для обычных именованных методов могут быть созданы с помощью оператора AddressOf, что я и делаю в большинстве случаев в примерах, на которые я ссылался в начале этого ответа. Лямбда-выражение - это еще один способ создания делегата для анонимного метода. Этот код подобен написанию именованного метода, содержащего этот код:

imageMutex.WaitOne()
pbCamera.Image = DirectCast(imageCamera.Clone(), Bitmap)
imageMutex.ReleaseMutex()

, а затем использование AddressOf для создания делегата для этого метода. Это работает так, что методы Invoke и BeginInvoke работают со своими волхвами c в фоновом режиме для переключения контекста в поток пользовательского интерфейса, а затем выполняют метод, на который ссылается делегат в этом потоке.

Если вы не уверены, как делегаты работают или могут работать, вам может быть интересно узнать, что они - волхвы c за событиями. Событие - это в основном собрание делегатов. Рассмотрим Click событие Button. Вы пишете в своей форме метод, который хотите выполнить при нажатии Button. Как Button может выполнить этот метод? Регистрация обработчика события фактически создает делегата, который ссылается на этот метод, и добавляет его в коллекцию для этого события. Когда Button вызывает событие, оно в основном перебирает коллекцию делегатов и вызывает каждого из них.

...