Должен ли я всегда блокировать статические методы? - PullRequest
0 голосов
/ 03 ноября 2011

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

А как же DoSomething , который не использует статические переменные вне метода? Тоже нуждается в блокировке?

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

Как сказал Паксдиабло:

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

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

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

Ответы [ 3 ]

1 голос
/ 03 ноября 2011

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

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

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

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

Итог, я не думаю, что вам нужен синхронизатор во втором методе.


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

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

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
0 голосов
/ 03 ноября 2011

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

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
0 голосов
/ 03 ноября 2011

Как правило, нет.

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

...