Оператор SyncLock

Получает монопольную блокировку блока инструкции перед выполнением блока.

Синтаксис

SyncLock lockobject  
    [ block ]  
End SyncLock  

Компоненты

lockobject
Обязательный. Выражение, результатом которого является ссылка на объект.

block
Необязательный элемент. Блок инструкций, выполняемых при получении блокировки.

End SyncLock
SyncLock Завершает блок.

Remarks

Эта SyncLock инструкция гарантирует, что несколько потоков не выполняют блок инструкции одновременно. SyncLock запрещает каждому потоку вводить блок до тех пор, пока другой поток не будет его выполнять.

Наиболее распространенным способом SyncLock является защита данных от одновременного обновления несколькими потоками. Если операторы, которые управляют данными, должны идти к завершению без прерывания, поместите их в SyncLock блок.

Блок инструкций, защищенный монопольной блокировкой, иногда называется критическим разделом.

Правила

  • Ветвления. Невозможно ветвь в SyncLock блок за пределами блока.

  • Значение объекта lock. Значение lockobject не может быть Nothing. Перед использованием объекта блокировки необходимо создать его в инструкции SyncLock .

    Невозможно изменить значение lockobject при выполнении SyncLock блока. Механизм требует, чтобы объект блокировки оставался неизменным.

  • Оператор Await нельзя использовать в блоке SyncLock .

Поведение

  • Механизм. Когда поток достигает инструкции SyncLock , он оценивает lockobject выражение и приостанавливает выполнение до тех пор, пока он не получит монопольную блокировку объекта, возвращаемого выражением. Когда другой поток достигает инструкции SyncLock , он не получает блокировку, пока первый поток не выполнит инструкцию End SyncLock .

  • Защищенные данные. Если lockobject это Shared переменная, монопольная блокировка предотвращает выполнение SyncLock потока в любом экземпляре класса во время выполнения любого другого потока. Это обеспечивает защиту данных, общих для всех экземпляров.

    Если lockobject это переменная экземпляра (не Shared), блокировка предотвращает выполнение потока, работающего в текущем экземпляре SyncLock , одновременно с другим потоком в том же экземпляре. Это защищает данные, обслуживаемые отдельным экземпляром.

  • Приобретение и выпуск. SyncLock Блок ведет себя как Try...Finally конструкция, в которой Try блок получает монопольную блокировкуlockobject, а Finally блок освобождает его. Из-за этого SyncLock блок гарантирует освобождение блокировки независимо от способа выхода из блока. Это верно даже в случае необработанного исключения.

  • Вызовы платформы. Блок SyncLock получает и освобождает монопольную блокировку путем вызова Enter и Exit методов Monitor класса в System.Threading пространстве имен.

Методики программирования

Выражение lockobject всегда должно вычислять объект, принадлежащий исключительно вашему классу. Необходимо объявить объектную Private переменную для защиты данных, принадлежащих текущему экземпляру, или Private Shared объектной переменной для защиты данных, общих для всех экземпляров.

Ключевое Me слово не следует использовать для предоставления объекта блокировки для данных экземпляра. Если код, внешний для вашего класса, имеет ссылку на экземпляр класса, он может использовать ее в качестве объекта блокировки для SyncLock блока, совершенно отличного от вашего, защищая разные данные. Таким образом, класс и другой класс могут блокировать выполнение несвязанных SyncLock блоков. Аналогичным образом блокировка строки может быть проблематичной, так как любой другой код в процессе, использующий ту же строку, будет использовать ту же блокировку.

Метод также не следует использовать Me.GetType для предоставления объекта блокировки для общих данных. Это связано с тем, что GetType всегда возвращает один и тот же Type объект для заданного имени класса. Внешний код может вызывать GetType класс и получать тот же объект блокировки, который вы используете. Это приведет к тому, что два класса блокируют друг друга из своих SyncLock блоков.

Примеры

Описание

В следующем примере показан класс, который поддерживает простой список сообщений. Он содержит сообщения в массиве и последний используемый элемент этого массива в переменной. Процедура addAnotherMessage увеличивает последний элемент и сохраняет новое сообщение. Эти две операции защищены операторами и End SyncLock операторамиSyncLock, так как после увеличения последнего элемента новое сообщение должно храниться до того, как любой другой поток снова сможет увеличить последний элемент.

simpleMessageList Если класс поделился одним списком сообщений среди всех его экземпляров, переменные и messagesLast будут объявлены messagesList как Shared. В этом случае переменная messagesLock также должна быть Sharedтакой, чтобы каждый экземпляр использовал один объект блокировки.

Код

Class simpleMessageList
    Public messagesList() As String = New String(50) {}
    Public messagesLast As Integer = -1
    Private messagesLock As New Object
    Public Sub addAnotherMessage(ByVal newMessage As String)
        SyncLock messagesLock
            messagesLast += 1
            If messagesLast < messagesList.Length Then
                messagesList(messagesLast) = newMessage
            End If
        End SyncLock
    End Sub
End Class

Описание

В следующем примере используются потоки и SyncLock. Если инструкция присутствует, блок инструкции SyncLock является критическим разделом и balance никогда не становится отрицательным числом. Вы можете закомментировать и SyncLockEnd SyncLock закомментировать инструкции, чтобы увидеть эффект выхода из ключевого SyncLock слова.

Код

Imports System.Threading

Module Module1

    Class Account
        Dim thisLock As New Object
        Dim balance As Integer

        Dim r As New Random()

        Public Sub New(ByVal initial As Integer)
            balance = initial
        End Sub

        Public Function Withdraw(ByVal amount As Integer) As Integer
            ' This condition will never be true unless the SyncLock statement
            ' is commented out:
            If balance < 0 Then
                Throw New Exception("Negative Balance")
            End If

            ' Comment out the SyncLock and End SyncLock lines to see
            ' the effect of leaving out the SyncLock keyword.
            SyncLock thisLock
                If balance >= amount Then
                    Console.WriteLine("Balance before Withdrawal :  " & balance)
                    Console.WriteLine("Amount to Withdraw        : -" & amount)
                    balance = balance - amount
                    Console.WriteLine("Balance after Withdrawal  :  " & balance)
                    Return amount
                Else
                    ' Transaction rejected.
                    Return 0
                End If
            End SyncLock
        End Function

        Public Sub DoTransactions()
            For i As Integer = 0 To 99
                Withdraw(r.Next(1, 100))
            Next
        End Sub
    End Class

    Sub Main()
        Dim threads(10) As Thread
        Dim acc As New Account(1000)

        For i As Integer = 0 To 9
            Dim t As New Thread(New ThreadStart(AddressOf acc.DoTransactions))
            threads(i) = t
        Next

        For i As Integer = 0 To 9
            threads(i).Start()
        Next
    End Sub

End Module

Комментарии

См. также раздел