Безопасно использовать NSLock в основном потоке?

У меня есть глобальная переменная, доступ к которой осуществляется из нескольких потоков, в том числе из основного потока. Я бы хотел использовать NSLock, потому что он быстрее, чем GCD.

Вот что я пытаюсь сделать:

struct SynchronizedLock<Value> {
    private var _value: Value
    private var lock = NSLock()

    init(_ value: Value) {
        self._value = value
    }

    var value: Value {
        get { lock.synchronized { _value } }
        set { lock.synchronized { _value = newValue } }
    }

    mutating func synchronized<T>(block: (inout Value) throws -> T) rethrows -> T {
        return try lock.synchronized {
            try block(&_value)
        }
    }
}

extension NSLocking {
    func synchronized<T>(block: () throws -> T) rethrows -> T {
        lock()
        defer { unlock() }
        return try block()
    }
}

Будет ли NSLock блокировать основной поток или его безопасно использовать в основном потоке? Также такая же ситуация с DispatchSemaphore и следует ли прибегать к очередям?


person TruMan1    schedule 04.10.2019    source источник
comment
Это зависит от того, как ваши потоки его используют. Если это рекурсивно, вам, вероятно, нужно искать NSRecursiveLock. Если нет, то вам просто нужно убедиться, что вызов блокировки/разблокировки поступает из того же потока.   -  person VVB    schedule 04.10.2019


Ответы (1)


Да, безопасно использовать NSLock из любого потока, включая основной поток. Единственное ограничение с NSLock заключается в том, что вы должны разблокировать его из того же потока, в котором вы его заблокировали, что вы и делаете здесь.

Будет ли NSLock блокировать основной поток или его безопасно использовать в основном потоке?

Очевидно, что если вы заблокируете основной поток на какой-то продолжительный период времени, это будет проблематично. Поэтому убедитесь, что вы всегда входите и выходите очень быстро. Всегда избегайте блокировки (или блокировки) в течение длительного периода времени.

Также такая же ситуация с DispatchSemaphore и следует ли прибегать к очередям?

Любой механизм синхронизации может заблокировать поток, из которого они используются, поэтому это в значительной степени проблематично независимо от механизма синхронизации. DispatchSemaphore или последовательные очереди GCD будут иметь ту же проблему, что и этот шаблон блокировки.

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

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

person Rob    schedule 04.10.2019