Использует ли @синхронизировать не использование "блокировки" и "разблокировки" для достижения взаимного исключения? Как он блокируется/разблокируется?
Вывод следующей программы - это только "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];
}
Ответ 1
Синхронизация языкового уровня Objective-C использует мьютекс, как это делает NSLock
. Семантически существуют некоторые небольшие технические отличия, но в принципе правильно думать о них как о двух отдельных интерфейсах, реализованных поверх общего (более примитивного) объекта.
В частности, с NSLock
у вас есть явная блокировка, тогда как с @synchronized
у вас есть неявный блокировка, связанная с объектом, который вы используете для синхронизации. Преимущество блокировки языкового уровня заключается в том, что компилятор понимает это, поэтому он может справляться с проблемами определения области обзора, но механически они ведут себя в основном одинаково.
Вы можете думать о @synchronized
как переписывать компилятор:
- (NSString *)myString {
@synchronized(self) {
return [[myString retain] autorelease];
}
}
преобразуется в:
- (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;
}
Это не совсем правильно, потому что фактическое преобразование более сложное и использует рекурсивные блокировки, но оно должно получить точку.
Ответ 2
В Objective-C блок @synchronized
автоматически обрабатывает блокировку и разблокировку (а также возможные исключения). Время выполнения динамически существенно генерирует NSRecursiveLock, связанный с объектом, на котором вы синхронизируете. Эта документация Apple объясняет это более подробно. Вот почему вы не видите сообщения журнала из вашего подкласса NSLock - объект, который вы синхронизируете, может быть чем угодно, а не только NSLock.
В принципе, @synchronized (...)
- это конструкция удобства, которая упрощает ваш код. Как и большинство упрощающих абстракций, это связано с накладными расходами (подумайте об этом как о скрытой стоимости), и хорошо знать об этом, но сырая производительность, вероятно, не является высшей целью при использовании таких конструкций в любом случае.
Ответ 3
На самом деле
{
@synchronized(self) {
return [[myString retain] autorelease];
}
}
преобразуется непосредственно в:
// needs #import <objc/objc-sync.h>
{
objc_sync_enter(self)
id retVal = [[myString retain] autorelease];
objc_sync_exit(self);
return retVal;
}
Этот API доступен с iOS 2.0 и импортируется с помощью...
#import <objc/objc-sync.h>
Ответ 4
Реализация Apple @synchronized является открытым исходным кодом, и ее можно найти здесь. Майк пепел написал два действительно интересных сообщения об этой теме:
В двух словах она имеет таблицу, которая сопоставляет указатели объектов (используя их адреса памяти как ключи) на блокировки pthread_mutex_t
, которые блокируются и разблокируются по мере необходимости.
Ответ 5
Он просто связывает семафор с каждым объектом и использует его.