Должен ли я всегда блокировать статические методы?

#vb.net #static #locking #thread-safety #shared

#vb.net #статические #блокировка #безопасность потоков #общий

Вопрос:

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

Но как насчет doSomething, который не использует никаких статических переменных вне метода? Нужна ли блокировка тоже?

РЕДАКТИРОВАТЬ: я хотел бы уточнить, что в данном конкретном случае я ожидаю, что doSomething всегда будет последовательно печатать 0-100 (т. Е. Нет 0123745 …) независимо от количества вызывающих потоков. Или, в общем, разные потоки не влияют на переменные друг друга (вывод на консоль — это только пример). Язык в следующем примере VB.NET .

Как сказал paxdiablo:

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

Это именно то, что я пытался решить. Спасибо!

 Public Class TestClass

    Private Shared lock As New Object
    Private Shared list As List(Of Integer)

    Public Shared Function GetList() As List(Of Integer)

        SyncLock lock
            If list Is Nothing Then
                list = New List(Of Integer)
            End If
            Return list
        End SyncLock

    End Function

    Public Shared Sub DoSomething()

        Dim i As Integer

        For i = 0 To 100
            Console.WriteLine(i.ToString)
        Next

    End Sub

End Class
  

Ответ №1:

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

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

Конечно, можно утверждать, что консоль также является ресурсом и может нуждаться в защите, если, например, вы не хотите, чтобы строки мешали друг другу (синхронизировать запись) или хотели, чтобы все сто строк выводились как единое целое (синхронизировать весь цикл for).

Но на самом деле это не защитит консоль, а только блок кода, который ее использует. Другие потоки по-прежнему смогут выполнять запись в консоль, не используя этот метод.

Итог, я не думаю, что вам нужен synclock во втором методе.


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

Я был бы немного обеспокоен вашим размещением synclock в первом методе, особенно если оператор return был передачей управления обратно вызывающему (и synclock не разблокировался автоматически при изменении области видимости). Похоже, вы можете вернуться без разблокировки, что было бы катастрофой. Я бы подумал, что более подходящим будет следующее:

 Public Shared Function GetList() As List(Of Integer)
    SyncLock lock
        If list Is Nothing Then
            list = New List(Of Integer)
        End If
    End SyncLock
    Return list
End Function
  

Комментарии:

1. Я думаю, что @pst правильно переименовать как VB.Net . Synclock в VB. Net эквивалентен lock в C # и имеет те же гарантии разблокировки

Ответ №2:

В общем, нет.

Вы должны четко понимать причину, по GetList которой применяется блокировка. Это не так, как вы подразумеваете в своем первом предложении, потому что оно возвращает статическую переменную. Вы могли бы удалить код блокировки и GetList все равно были бы потокобезопасными. Но с блокировкой есть дополнительная гарантия — список будет создан только один раз, и все вызывающие этот код получат ссылку на один и тот же список.

Ответ №3:

Почему бы вообще не избежать блокировки и просто сделать это:

 Public Class TestClass

    Private Shared lock As New Object
    Private Shared list As New List(Of Integer)

    Public Shared Function GetList() As List(Of Integer)
        Return list
    End Function

    Public Shared Sub DoSomething()
        Dim i As Integer
        For i = 0 To 100
            Console.WriteLine(i.ToString)
        Next
    End Sub

End Class
  

Комментарии:

1. Раздел getList упоминается только в качестве предисловия к части doSomething. Вероятно, я должен был пропустить это, поскольку это скорее сбивает с толку, чем проясняет.