Jak @synchronized blokuje / odblokowuje w Objective-C?

Czy @synchronized nie używa "lock" I "unlock", aby osiągnąć wzajemne wykluczenie? Jak to zrobić, aby zablokować / odblokować następnie?

Wynikiem następującego programu jest tylko "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];
}
Author: David Lin, 2009-07-31

5 answers

SYNCHRONIZACJA poziomu języka Objective-C wykorzystuje mutex, tak jak robi to NSLock. Semantycznie istnieją pewne niewielkie różnice techniczne, ale zasadniczo poprawne jest myślenie o nich jako o dwóch oddzielnych interfejsach zaimplementowanych na wspólnej (bardziej prymitywnej) jednostce.

W szczególności z NSLock masz jawną blokadę, podczas gdy z {[4] } masz ukrytą blokadę związaną z obiektem, którego używasz do synchronizacji. Zaletą blokowania poziomu językowego jest kompilator rozumie to, więc może radzić sobie z problemami z zakresami, ale mechanicznie zachowują się zasadniczo tak samo.

Możesz myśleć o @synchronized jako o przepisaniu kompilatora:

- (NSString *)myString {
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

Przekształca się w:

- (NSString *)myString {
  NSString *retval = nil;
  pthread_mutex_t *self_mutex = LOOK_UP_MUTEX(self);
  pthread_mutex_lock(self_mutex);
  retval = [[myString retain] autorelease];
  pthread_mutex_unlock(self_mutex);
  return retval;
}

To nie jest do końca poprawne, ponieważ rzeczywista transformacja jest bardziej złożona i używa rekurencyjnych blokad, ale powinna uzyskać punkt w poprzek.

 327
Author: Louis Gerbarg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-25 23:28:52

W Objective-C, Blok @synchronized automatycznie blokuje i odblokowuje (jak również możliwe wyjątki). Runtime dynamicznie generuje NSRecursiveLock, który jest powiązany z obiektem, na którym synchronizujesz. ta dokumentacja Apple wyjaśnia to bardziej szczegółowo. Dlatego nie widzisz wiadomości logów z podklasy NSLock - obiekt, na którym synchronizujesz, może być wszystkim, a nie tylko NSLock.

Zasadniczo, @synchronized (...) jest wygodą skonstruować, że usprawnia swój kod. Podobnie jak większość uproszczonych abstrakcji, wiąże się z overhead( pomyśl o tym jako o ukrytym koszcie), i dobrze jest mieć tego świadomość, ale surowa wydajność prawdopodobnie nie jest najwyższym celem przy użyciu takich konstrukcji i tak.

 41
Author: Quinn Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-11 11:59:45

Właściwie

{
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

Przekształca się bezpośrednio w:

// needs #import <objc/objc-sync.h>
{
  objc_sync_enter(self)
    id retVal = [[myString retain] autorelease];
  objc_sync_exit(self);
  return retVal;
}

To API dostępne od iOS 2.0 i importowane za pomocą...

#import <objc/objc-sync.h>
 31
Author: Dirk Theisen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-26 19:57:52

Implementacja @synchronized firmy Apple jest open source i można ją znaleźć Tutaj . Mike ash napisał dwa bardzo ciekawe posty na ten temat:

W skrócie zawiera tabelę, która mapuje wskaźniki obiektów (używając ich adresów pamięci jako kluczy) na pthread_mutex_t blokady, które są blokowane i odblokowywane w razie potrzeby.

 3
Author: JP Illanes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 09:37:37

Po prostu kojarzy SEMAFOR z każdym obiektem i używa go.

 -4
Author: Pavel Minaev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 23:37:04