@Synchronized n'utilise-t-il pas "verrouiller" et "déverrouiller" pour réaliser l'exclusion mutuelle? Comment ça se verrouille / déverrouille alors?
La sortie du programme suivant est uniquement "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
la source
la source
lock
objet est créé à chaque appel, il n'y aura donc jamais de cas où un@synchronized
bloc en verrouille un autre. Et cela signifie qu'il n'y a pas d'exclusion mutuelle.) Bien sûr, l'exemple ci-dessus fait l'opération enmain
, donc il n'y a rien à exclure de toute façon, mais il ne faut pas copier aveuglément ce code ailleurs.Réponses:
La synchronisation au niveau du langage Objective-C utilise le mutex, tout comme le
NSLock
fait. Sémantiquement, il existe de petites différences techniques, mais il est fondamentalement correct de les considérer comme deux interfaces distinctes implémentées au-dessus d'une entité commune (plus primitive).En particulier avec un,
NSLock
vous avez un verrou explicite tandis qu'avec@synchronized
vous avez un verrou implicite associé à l'objet que vous utilisez pour synchroniser. L'avantage du verrouillage au niveau du langage est que le compilateur le comprend afin qu'il puisse traiter les problèmes de portée, mais mécaniquement, ils se comportent essentiellement de la même manière.Vous pouvez penser
@synchronized
à une réécriture du compilateur:se transforme en:
Ce n'est pas exactement correct car la transformation réelle est plus complexe et utilise des verrous récursifs, mais elle devrait faire passer le message.
la source
Dans Objective-C, un
@synchronized
bloc gère automatiquement le verrouillage et le déverrouillage (ainsi que les exceptions possibles). Le runtime génère dynamiquement essentiellement un NSRecursiveLock qui est associé à l'objet sur lequel vous effectuez la synchronisation. Cette documentation Apple l' explique plus en détail. C'est pourquoi vous ne voyez pas les messages de journal de votre sous-classe NSLock - l'objet sur lequel vous synchronisez peut être n'importe quoi, pas seulement un NSLock.Fondamentalement,
@synchronized (...)
c'est une construction pratique qui rationalise votre code. Comme la plupart des abstractions simplificatrices, il a associé des frais généraux (pensez-y comme un coût caché), et il est bon d'en être conscient, mais les performances brutes ne sont probablement pas l'objectif suprême lors de l'utilisation de telles constructions de toute façon.la source
Réellement
se transforme directement en:
Cette API disponible depuis iOS 2.0 et importée en utilisant ...
la source
@synchronized
bloc ajoute implicitement un gestionnaire d'exceptions au code protégé. Ce gestionnaire libère automatiquement le mutex en cas de levée d'une exception."L'implémentation d'Apple de @synchronized est open source et vous pouvez la trouver ici . Mike Ash a écrit deux articles très intéressants sur ce sujet:
En bref, il a une table qui mappe les pointeurs d'objets (en utilisant leurs adresses mémoire comme clés) sur les
pthread_mutex_t
verrous, qui sont verrouillés et déverrouillés selon les besoins.la source
Il associe simplement un sémaphore à chaque objet et l'utilise.
la source