Ich habe das Swift-Buch durchsucht, kann aber die Swift-Version von @synchronized nicht finden. Wie kann ich mich in Swift gegenseitig ausschließen?
concurrency
mutex
swift
Rechnung
quelle
quelle
removeFirst()
?Antworten:
Sie können GCD verwenden. Es ist etwas ausführlicher als
@synchronized
, funktioniert aber als Ersatz:quelle
Ich habe selbst danach gesucht und bin zu dem Schluss gekommen, dass es dafür noch kein natives Konstrukt innerhalb von Swift gibt.
Ich habe diese kleine Hilfsfunktion basierend auf dem Code erfunden, den ich von Matt Bridges und anderen gesehen habe.
Die Verwendung ist ziemlich einfach
Es gibt ein Problem, das ich damit gefunden habe. Die Übergabe eines Arrays als Sperrargument scheint an dieser Stelle einen sehr stumpfen Compilerfehler zu verursachen. Ansonsten scheint es aber wie gewünscht zu funktionieren.
quelle
@synchronized
Blocks gut, aber beachten Sie, dass sie nicht mit einer echten eingebauten Blockanweisung wie dem@synchronized
Block in Objective-C identisch ist , dareturn
undbreak
Anweisungen nicht mehr funktionieren, um aus der umgebenden Funktion / Schleife herauszuspringen es wäre, wenn dies eine gewöhnliche Aussage wäre.defer
Schlüsselwort zu verwenden, um sicherzustellenobjc_sync_exit
, dass es auch beiclosure
Würfen aufgerufen wird .Ich mag und verwende viele der Antworten hier, also würde ich wählen, welche für Sie am besten funktioniert. Die Methode, die ich bevorzuge, wenn ich so etwas wie Objective-Cs benötige,
@synchronized
verwendet diedefer
in Swift 2 eingeführte Aussage.Das Schöne an dieser Methode ist , dass Ihr kritischer Abschnitt den umschließende Block in jeder gewünschten Weise verlassen kann (zB
return
,break
,continue
,throw
) und „die Aussagen in der Zurückstellungs Anweisung unabhängig davon ausgeführt , wie die Programmsteuerung übertragen wird.“ 1quelle
lock
? Wie wirdlock
initialisiert?lock
ist ein objektives Objekt.Sie können Anweisungen zwischen
objc_sync_enter(obj: AnyObject?)
und einfügenobjc_sync_exit(obj: AnyObject?)
. Das Schlüsselwort @synchronized verwendet diese Methoden unter dem Deckmantel. dhquelle
objc_sync_enter
undobjc_sync_exit
sind Methoden, die in Objc-sync.h definiert sind und Open Source sind: opensource.apple.com/source/objc4/objc4-371.2/runtime/…objc_sync_enter(…)
&objc_sync_exit(…)
sind öffentliche Header, die von iOS / macOS / etc. APIs (sieht aus, als ob sie sich….sdk
im Pfad befindenusr/include/objc/objc-sync.h
) . Der einfachste Weg, um herauszufinden, ob etwas eine öffentliche API ist oder nicht, besteht darin, (in Xcode) den Funktionsnamen einzugeben (zobjc_sync_enter()
. B. müssen für C-Funktionen keine Argumente angegeben werden) und dann mit der Befehlstaste darauf zu klicken. Wenn es Ihnen die Header-Datei für diese API zeigt, sind Sie gut (da Sie den Header nicht sehen könnten, wenn er nicht öffentlich wäre) .Analog zur
@synchronized
Direktive von Objective-C kann esrethrows
in Swift einen beliebigen Rückgabetyp und ein nettes Verhalten geben.Durch die Verwendung der
defer
Anweisung können Sie einen Wert direkt zurückgeben, ohne eine temporäre Variable einzuführen.Fügen Sie in Swift 2 das
@noescape
Attribut zum Abschluss hinzu, um weitere Optimierungen zu ermöglichen:Basierend auf den Antworten von GNewc [1] (wo ich einen beliebigen Rückgabetyp mag) und Tod Cunningham [2] (wo ich mag
defer
).quelle
SWIFT 4
In Swift 4 können Sie GCDs-Versandwarteschlangen verwenden, um Ressourcen zu sperren.
quelle
.serial
scheint nicht verfügbar zu sein. Ist.concurrent
aber vorhanden. : /myObject.state = myObject.state + 1
gleichzeitig ausgeführt werden, werden nicht die Gesamtoperationen gezählt, sondern ein nicht deterministischer Wert ausgegeben. Um dieses Problem zu lösen, sollte der aufrufende Code in eine serielle Warteschlange eingeschlossen werden, damit sowohl das Lesen als auch das Schreiben atomar erfolgen. Natürlich hat Obj-c's@synchronised
das gleiche Problem, also ist Ihre Implementierung in diesem Sinne korrekt.myObject.state += 1
ist eine Kombination aus einer Lese- und einer Schreiboperation. Dazwischen kann noch ein anderer Thread stehen, um einen Wert zu setzen / zu schreiben. Wie pro objc.io/blog/2018/12/18/atomic-variables , wäre es einfacher, die läuftset
in einem Synchronisationsblock / Schließung statt und nicht unter der Variable selbst.Um die Rückgabefunktionalität hinzuzufügen, können Sie Folgendes tun:
Anschließend können Sie es aufrufen mit:
quelle
Mit der Antwort von Bryan McLemore habe ich sie erweitert, um Objekte zu unterstützen, die ein sicheres Herrenhaus mit der Swift 2.0-Aufschubfähigkeit bieten.
quelle
rethrows
die Verwendung mit nicht werfenden Verschlüssen zu vereinfachen (keine Verwendung erforderlichtry
), wie in meiner Antwort gezeigt .Swift 3
Dieser Code kann erneut eingegeben werden und kann mit asynchronen Funktionsaufrufen arbeiten. In diesem Code wird nach dem Aufruf von someAsyncFunc () ein weiterer Funktionsabschluss in der seriellen Warteschlange verarbeitet, jedoch von semaphore.wait () blockiert, bis signal () aufgerufen wird. internalQueue.sync sollte nicht verwendet werden, da es den Hauptthread blockiert, wenn ich mich nicht irre.
objc_sync_enter / objc_sync_exit ist ohne Fehlerbehandlung keine gute Idee.
quelle
In der Sitzung 414 "Grundlegendes zu Abstürzen und Absturzprotokollen" des WWDC 2018 wird die folgende Methode zur Verwendung von DispatchQueues mit Synchronisierung gezeigt.
In Swift 4 sollte so etwas wie das Folgende sein:
Auf jeden Fall können Sie Lesevorgänge auch durch gleichzeitige Warteschlangen mit Barrieren beschleunigen. Synchronisierungs- und Asynchronisierungslesevorgänge werden gleichzeitig ausgeführt, und das Schreiben eines neuen Werts wartet, bis die vorherigen Vorgänge abgeschlossen sind.
quelle
Verwenden Sie NSLock in Swift4:
quelle
Im modernen Swift 5 mit Rückgabefähigkeit:
Verwenden Sie es wie folgt, um die Rückgabewertfunktion zu nutzen:
Oder anders anders:
quelle
GCD
). Es scheint, dass im Wesentlichen niemand etwas benutzt oder versteht, wie man es benutztThread
. Ich bin sehr zufrieden damit - währendGCD
es mit Fallstricken und Einschränkungen behaftet ist.Versuchen Sie: NSRecursiveLock
quelle
Abbildung Ich werde meine Swift 5-Implementierung veröffentlichen, die auf den vorherigen Antworten basiert. Danke Leute! Ich fand es hilfreich, eine zu haben, die auch einen Wert zurückgibt, also habe ich zwei Methoden.
Hier ist eine einfache Klasse, die zuerst erstellt werden muss:
Verwenden Sie es dann wie folgt, wenn Sie einen Rückgabewert benötigen:
Oder:
quelle
public class func synced<T>(_ lock: Any, closure: () -> T)
, funktioniert sowohl für void als auch für jeden anderen Typ. Es gibt auch das Nachwachsen Zeug.Einzelheiten
xCode 8.3.1, schnell 3.1
Aufgabe
Schreibwert von verschiedenen Threads lesen (asynchron).
Code
Verwendung
Vollständige Probe
quelle
Mit Swifts Property Wrappern verwende ich Folgendes:
Dann können Sie einfach tun:
oder
Greifen Sie dann wie gewohnt auf die Variable zu.
quelle
DispatchQueue
die dem Benutzer verborgen bleibt. Ich fand diese SO-Referenz, um mich zu beruhigenAbschließend geben Sie hier einen allgemeineren Weg an, der Rückgabewert oder void enthält, und werfen
quelle
Warum es schwierig machen und mit Schlössern Ärger machen? Verwenden Sie Versandbarrieren.
Eine Versandbarriere erstellt einen Synchronisationspunkt innerhalb einer gleichzeitigen Warteschlange.
Während der Ausführung darf kein anderer Block in der Warteschlange ausgeführt werden, selbst wenn er gleichzeitig ausgeführt wird und andere Kerne verfügbar sind.
Wenn das nach einer exklusiven (Schreib-) Sperre klingt, ist es das auch. Nicht-Barriere-Blöcke können als gemeinsam genutzte (Lese-) Sperren betrachtet werden.
Solange der gesamte Zugriff auf die Ressource über die Warteschlange erfolgt, bieten Barrieren eine sehr kostengünstige Synchronisation.
quelle
Testen Sie anhand von „Neurobur“ einen Fall der Unterklasse
Ausgabe:
quelle
dispatch_barrier_async ist der bessere Weg, ohne den aktuellen Thread zu blockieren.
dispatch_barrier_async (accessQueue, {dictionary [object.ID] = object})
quelle
Eine andere Methode besteht darin, eine Oberklasse zu erstellen und diese dann zu erben. Auf diese Weise können Sie GCD direkter verwenden
quelle