Verwendet @synchronized nicht "Sperren" und "Entsperren", um einen gegenseitigen Ausschluss zu erreichen? Wie sperrt / entsperrt es dann?
Die Ausgabe des folgenden Programms ist nur "Hello World".
@interface MyLock: NSLock<NSLocking>
@end
@implementation MyLock
- (id)init {
return [super init];
}
- (void)lock {
NSLog(@"before lock");
[super lock];
NSLog(@"after lock");
}
- (void)unlock {
NSLog(@"before unlock");
[super unlock];
NSLog(@"after unlock");
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MyLock *lock = [[MyLock new] autorelease];
@synchronized(lock) {
NSLog(@"Hello World");
}
[pool drain];
}
objective-c
synchronization
David Lin
quelle
quelle
lock
Objekt wird bei jedem Aufruf erstellt, sodass es niemals einen Fall gibt, in dem ein@synchronized
Block einen anderen sperrt. Und das bedeutet, dass es keinen gegenseitigen Ausschluss gibt.) Natürlich führt das obige Beispiel die Operation in ausmain
, daher gibt es sowieso nichts auszuschließen, aber man sollte diesen Code nicht blind an eine andere Stelle kopieren.Antworten:
Die Synchronisation auf Objective-C-Sprachebene verwendet genau wie
NSLock
sie den Mutex . Semantisch gibt es einige kleine technische Unterschiede, aber es ist grundsätzlich richtig, sie als zwei separate Schnittstellen zu betrachten, die auf einer gemeinsamen (primitiveren) Entität implementiert sind.Insbesondere mit a haben
NSLock
Sie eine explizite Sperre, während mit@synchronized
Ihnen eine implizite Sperre für das Objekt verknüpft ist, mit dem Sie synchronisieren. Der Vorteil der Sperre auf Sprachebene besteht darin, dass der Compiler sie versteht, damit er sich mit Scoping-Problemen befassen kann, sich mechanisch jedoch grundsätzlich gleich verhält.Sie können sich
@synchronized
ein Compiler-Rewrite vorstellen:verwandelt sich in:
Das ist nicht genau richtig, da die eigentliche Transformation komplexer ist und rekursive Sperren verwendet, aber es sollte den Punkt vermitteln.
quelle
In Objective-C
@synchronized
übernimmt ein Block das Sperren und Entsperren (sowie mögliche Ausnahmen) automatisch für Sie. Die Laufzeit generiert im Wesentlichen dynamisch ein NSRecursiveLock, das dem Objekt zugeordnet ist, auf dem Sie synchronisieren. In dieser Apple-Dokumentation wird dies ausführlicher erläutert. Aus diesem Grund werden die Protokollnachrichten Ihrer NSLock-Unterklasse nicht angezeigt. Das Objekt, für das Sie synchronisieren, kann alles sein, nicht nur ein NSLock.Grundsätzlich
@synchronized (...)
handelt es sich um ein Convenience-Konstrukt, das Ihren Code rationalisiert. Wie bei den meisten vereinfachenden Abstraktionen ist damit ein Overhead verbunden (stellen Sie sich dies als versteckte Kosten vor), und es ist gut, sich dessen bewusst zu sein, aber die rohe Leistung ist wahrscheinlich nicht das oberste Ziel, wenn Sie solche Konstrukte verwenden.quelle
Tatsächlich
verwandelt sich direkt in:
Diese API ist seit iOS 2.0 verfügbar und wird importiert mit ...
quelle
@synchronized
fügt der Block dem geschützten Code implizit einen Ausnahmehandler hinzu. Dieser Handler gibt den Mutex automatisch frei, falls eine Ausnahme ausgelöst wird."Apples Implementierung von @synchronized ist Open Source und kann hier gefunden werden . Mike Ash hat zwei wirklich interessante Beiträge zu diesem Thema geschrieben:
Kurz gesagt, es gibt eine Tabelle, die Objektzeiger (unter Verwendung ihrer Speicheradressen als Schlüssel)
pthread_mutex_t
Sperren zuordnet, die nach Bedarf gesperrt und entsperrt werden.quelle
Es ordnet jedem Objekt einfach ein Semaphor zu und verwendet es.
quelle