Я искал книгу Swift, но не могу найти версию @synchronized Swift. Как сделать взаимное исключение в Swift?
concurrency
mutex
swift
Билл
источник
источник
removeFirst()
?Ответы:
Вы можете использовать GCD. Это немного более многословно
@synchronized
, но работает как замена:источник
Я сам искал это и пришел к выводу, что внутри swift пока нет нативной конструкции.
Я сделал эту маленькую вспомогательную функцию на основе некоторого кода, который я видел от Мэтта Бриджеса и других.
Использование довольно просто
Есть одна проблема, которую я нашел с этим. Передача массива в качестве аргумента блокировки, кажется, вызывает очень тупую ошибку компилятора на этом этапе. В противном случае, хотя, кажется, работает как хотелось бы.
источник
@synchronized
блока хорошо, но обратите внимание , что это не совпадает с утверждением блока реального встроено как в@synchronized
блоке в Objective-C, такreturn
иbreak
заявлений больше не будет работать , чтобы выскочить из окружающей функции / петли , как было бы, если бы это было обычное утверждение.defer
ключевого слова, чтобы гарантировать, чтоobjc_sync_exit
вызов будет вызван, даже еслиclosure
throws.Мне нравятся и используются многие ответы здесь, поэтому я бы выбрал тот, который подходит вам лучше всего. Тем не менее, метод, который я предпочитаю, когда мне нужно что-то вроде target-c,
@synchronized
используетdefer
оператор, введенный в swift 2.Хорошая вещь об этом методе является то , что ваша критическая секция может выйти из блока , содержащего каким - либо образом желаемому (например,
return
,break
,continue
,throw
), а также «заявления в рамках заявления Defer выполняются независимо от того , каким образом передается управление программой.» 1источник
lock
? Какlock
инициализируется?lock
это любой объект-объект.Вы можете сэндвич заявления между
objc_sync_enter(obj: AnyObject?)
иobjc_sync_exit(obj: AnyObject?)
. Ключевое слово @synchronized использует эти методы под прикрытием. т.е.источник
objc_sync_enter
иobjc_sync_exit
это методы, определенные в Objc-sync.h и с открытым исходным кодомobjc_sync_enter(…)
иobjc_sync_exit(…)
являются открытыми заголовки , предоставляемые КСН / MacOS / и т.д.. API (похоже, они находятся внутри….sdk
путиusr/include/objc/objc-sync.h
) . Самый простой способ выяснить, является ли что-то общедоступным API или нет, состоит в том, чтобы (в Xcode) ввести имя функции (напримерobjc_sync_enter()
, аргументы не нужно указывать для функций C) , а затем попытаться щелкнуть по нему командой. Если он показывает вам заголовочный файл для этого API, то у вас все хорошо (поскольку вы не сможете увидеть заголовок, если он не будет публичным) .Аналог
@synchronized
директивы из Objective-C может иметь произвольный тип возвращаемого значения и хорошееrethrows
поведение в Swift.Использование
defer
оператора позволяет напрямую возвращать значение, не вводя временную переменную.В Swift 2 добавьте
@noescape
атрибут в замыкание, чтобы позволить больше оптимизаций:Основано на ответах из GNewc [1] (где мне нравится произвольный тип возврата) и Тода Каннингема [2] (где мне нравится
defer
).источник
SWIFT 4
В Swift 4 вы можете использовать очереди отправки GCD для блокировки ресурсов.
источник
.serial
кажется недоступным. Но.concurrent
есть в наличии. : /myObject.state = myObject.state + 1
одновременно, он не будет подсчитывать общее количество операций, а вместо этого даст недетерминированное значение. Чтобы решить эту проблему, вызывающий код должен быть помещен в последовательную очередь, чтобы и чтение, и запись происходили атомарно. Конечно, у Obj-c@synchronised
та же проблема, поэтому в этом смысле ваша реализация верна.myObject.state += 1
это комбинация операции чтения и записи. Какой-то другой поток все еще может находиться между ними для установки / записи значения. Согласно objc.io/blog/2018/12/18/atomic-variables было бы прощеset
вместо этого запускать в блоке / закрытии синхронизации, а не в самой переменной.Используя ответ Брайана МакЛемора, я расширил его, чтобы он поддерживал объекты, которые бросают в безопасное поместье со способностью отсрочки Swift 2.0.
источник
rethrows
чтобы упростить использование с не-бросающими замыканиями (не нужно использоватьtry
), как показано в моем ответе .Чтобы добавить возвращаемую функциональность, вы можете сделать это:
Впоследствии вы можете позвонить, используя:
источник
Свифт 3
Этот код имеет возможность повторного ввода и может работать с асинхронными вызовами функций. В этом коде после вызова someAsyncFunc () другая функция закрытия в последовательной очереди будет обрабатываться, но будет блокироваться semaphore.wait () до вызова signal (). innerQueue.sync не должен использоваться, поскольку он заблокирует основной поток, если я не ошибаюсь.
objc_sync_enter / objc_sync_exit - плохая идея без обработки ошибок.
источник
В сеансе «Понимание сбоев и журналов сбоев» 414 WWDC 2018 года они показывают следующий способ, используя DispatchQueues с синхронизацией.
В swift 4 должно быть что-то вроде следующего:
В любом случае вы также можете ускорить чтение, используя параллельные очереди с барьерами. Синхронное и асинхронное чтение выполняются одновременно, и запись нового значения ожидает завершения предыдущих операций.
источник
Используйте NSLock в Swift4:
источник
В современном Swift 5 с возможностью возврата:
Используйте это так, чтобы воспользоваться возможностью возврата значения:
Или как то иначе:
источник
GCD
). Кажется, по существу никто не использует или не понимает, как использоватьThread
. Я очень доволен этим - тогдаGCD
как чревато недостатками и ограничениями.Попробуйте: NSRecursiveLock
источник
Рисунок Я опубликую свою реализацию Swift 5, основанную на предыдущих ответах. Спасибо, парни! Я считаю полезным иметь такой, который тоже возвращает значение, поэтому у меня есть два метода.
Вот простой класс, который нужно сделать первым:
Затем используйте его так, если вам нужно возвращаемое значение:
Или:
источник
public class func synced<T>(_ lock: Any, closure: () -> T)
, работает как для void, так и для любого другого типа. Существует также материал для роста.подробности
xCode 8.3.1, swift 3.1
задача
Чтение значения записи из разных потоков (асинхронное).
Код
использование
Полный образец
источник
С оболочками свойств Swift, это то, что я сейчас использую:
Тогда вы можете просто сделать:
или
Затем получите доступ к переменной, как обычно.
источник
DispatchQueue
скрытого от пользователя. Я нашел эту ссылку, чтобы успокоиться: stackoverflow.com/a/35022486/1060314В заключение, здесь приведем более распространенный способ, который включает возвращаемое значение или пустоту, и бросить
источник
Зачем делать это сложно и хлопотно с замками? Используйте диспетчерские барьеры.
Диспетчерский барьер создает точку синхронизации в параллельной очереди.
Пока он работает, ни один другой блок в очереди не может быть запущен, даже если он работает одновременно и другие ядра доступны.
Если это звучит как эксклюзивная блокировка (запись), это так. Небарьерные блоки можно рассматривать как общие (читаемые) блокировки.
Пока весь доступ к ресурсу осуществляется через очередь, барьеры обеспечивают очень дешевую синхронизацию.
источник
На основе «eurobur» , протестируйте случай подкласса
Вывод:
источник
dispatch_barrier_async - лучший способ, не блокируя текущий поток.
dispatch_barrier_async (accessQueue, {словарь [object.ID] = объект})
источник
Другой метод заключается в создании суперкласса и его наследовании. Таким образом, вы можете использовать GCD более напрямую
источник