Sperren eines Objekts, auf das von mehreren Threads zugegriffen wird - Objective-C
Ich habe eine Frage bezüglich der thread-Sicherheit in Objective-C. ich habe gelesen, ein paar andere Antworten, die einige der Apple-Dokumentation, und haben noch einige Zweifel in Bezug auf diese, so dachte, ich würde Fragen, meine eigenen Fragen stellen.
Meine Frage ist drei Falten:
Angenommen ich habe ein array, NSMutableArray *myAwesomeArray;
Fach 1:
Nun korrigiert mich wenn ich mich Irre, aber von dem was ich verstehe, mit @synchronized(myAwesomeArray){...}
wird verhindern, dass zwei threads greifen auf die gleiche code-block. Also, im Grunde, wenn ich so etwas wie:
-(void)doSomething {
@synchronized(myAwesomeArray) {
//some read/write operation on myAwesomeArray
}
}
dann, wenn zwei threads den Zugriff auf die gleichen Methode, bei der die gleichen Zeit, dieser block von code thread-safe. Ich vermute, ich habe verstanden, dass dieses Teil richtig.
Fach 2:
Was mache ich, wenn myAwesomeArray
wird für den Zugriff durch mehrere threads aus verschiedenen Methoden?
Wenn ich so etwas wie:
- (void)readFromArrayAccessedByThreadOne {
//thread 1 reads from myAwesomeArray
}
- (void)writeToArrayAccessedByThreadTwo {
//thread 2 writes to myAwesomeArray
}
Nun werden die beiden Methoden werden aufgerufen, indem zwei verschiedene threads zur gleichen Zeit. Wie kann ich sicherstellen, dass myAwesomeArray
keine Probleme haben? Verwende ich so etwas wie NSLock oder NSRecursiveLock?
Fach 3:
Nun, in den beiden vorgenannten Fällen myAwesomeArray
war ein iVar in Erinnerung. Was ist, wenn ich habe eine Datenbank-Datei, die ich nicht immer im Gedächtnis behalten. Ich erstelle ein databaseManagerInstance
Wann immer ich will Datenbankoperationen ausführen, und geben Sie es, sobald ich fertig bin. Also, im Grunde, den verschiedenen Klassen auf die Datenbank zugreifen können. Jede Klasse erstellt eine eigene Instanz von DatabaseManger
, aber im Grunde sind Sie alle mit der gleichen, einzigen Datenbank-Datei. Wie kann ich sicherstellen, dass die Daten nicht beschädigt sind aufgrund von race conditions in einer solchen situation?
Dies wird mir helfen, löschen Sie einige meiner Grundlagen.
@synchronisieren
verhindert, dass andere threads greifen auf die gleiche variable, die Sie gesperrt haben, nicht, dass bestimmte code-block. InformationsquelleAutor der Frage codeBearer | 2012-06-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Fach 1
In der Regel verstehen, was
@synchronized
tut, ist richtig. Aber technisch gesehen, macht es keinen code "thread-safe". Es verhindert, dass andere threads aus aquiring die gleiche Sperre zur gleichen Zeit, aber Sie müssen sicherstellen, dass Sie immer die gleichen Synchronisations-token bei der Durchführung Kritischer Abschnitte. Wenn Sie das nicht tun, können Sie immer noch finden sich in der situation, wo zwei threads führen kritische Abschnitte in der gleichen Zeit. Überprüfen Sie die docs.Fach 2
Die meisten Menschen würden wahrscheinlich empfehlen, Sie zu verwenden NSRecursiveLock. Wenn ich du wäre, würde ich verwenden Sie GCD. Hier ist ein großartiges Dokument zeigt, wie die Migration von thread-Programmierung GCD-Programmierung, Ich denke, dass diese Herangehensweise an das problem ist eine viel bessere, als die, basierend auf NSLock. Kurz gesagt, erstellen Sie eine serielle queue und Versand Ihre Aufgaben in die Warteschlange. So gewährleisten Sie, dass Ihre kritischen Abschnitte behandelt werden Seriell, also es gibt nur einen kritischen Abschnitt ausgeführt zu einem bestimmten Zeitpunkt.
Fach 3
Dies ist das gleiche wie Fach 2, nur mehr bestimmte. Data base ist eine Ressource, die von vielen bedeutet es das gleiche wie bei der array-oder eine andere Sache. Wenn Sie sehen möchten der GCD-basierte Ansatz, in Datenbank-Programmierung context, werfen Sie einen Blick auf fmdb Umsetzung. Es tut genau das, was ich beschrieben in Fold2.
Als eine Randnotiz Fach 3, ich glaube nicht, dass die Instanziierung DatabaseManager jedes mal, wenn Sie wollen, verwenden Sie die Datenbank und dann die Freigabe es ist der richtige Ansatz. Ich denke, Sie sollten erstellen Sie eine einzige Datenbank-Verbindung und bewahren Sie Sie durch Ihre Anwendung-Sitzung. Auf diese Weise ist es einfacher, Sie zu verwalten. Wieder, fmdb ist ein großartiges Beispiel dafür, wie dies erreicht werden kann.
Bearbeiten
Wenn Sie das nicht möchten, verwenden Sie GCD dann ja, müssen Sie irgendeine Art von Verriegelung, und ja,
NSRecursiveLock
verhindert deadlocks, wenn Sie die Verwendung der Rekursion in Ihren Methoden, so ist es eine gute Wahl (es wird von@synchronized
). Es gibt jedoch einen Haken. Wenn es möglich ist, dass viele threads warten, für die gleiche Ressource, und die Reihenfolge, in der Sie erhalten Zugriff relevant ist, dannNSRecursiveLock
ist nicht genug. Sie können immer noch gelingt, diese situation mitNSCondition
, aber Vertrauen Sie mir, Sie sparen eine Menge Zeit mit GCD in diesem Fall. Wenn die Reihenfolge der threads ist nicht relevant, Sie sind sicher mit sperren.InformationsquelleAutor der Antwort lawicko
Als in Swift 3 in WWDC 2016-Sitzung 720 und der Gleichzeitigen Programmierung Mit GCD in Swift 3, sollten Sie
queue
InformationsquelleAutor der Antwort onmyway133
Subklasse NSMutableArray zu stellen sperren für den accessor (Lesen und schreiben) Methoden. So etwas wie:
Dieser Ansatz kapselt die sperren als Teil des Arrays. Benutzer brauchen nicht zu ändern Ihre Anrufe (aber möglicherweise müssen sich bewusst sein, dass Sie blockieren/warten für den Zugriff, wenn der Zugriff ist Zeit-kritisch). Ein wesentlicher Vorteil dieses Ansatzes ist, dass, wenn Sie entscheiden, dass Sie lieber nicht zu benutzen, sperren Sie können re-implementieren MySafeMutableArray zu verwenden dispatch-queues - oder was auch immer ist am besten für Ihr spezifisches problem. Zum Beispiel könnten Sie implementieren addObject:
Hinweis: wenn mithilfe von sperren, werden Sie sicherlich brauchen NSRecursiveLock, nicht NSLock, weil Sie nicht wissen, Objective-C Implementierungen von addObject usw. sind selbst rekursiv.
InformationsquelleAutor der Antwort GoZoner