难道@synchronized不使用“锁定”和“解锁”实现相互排斥? 它是如何做到的锁定/解锁呢?
以下程序的输出仅仅是“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语言水平同步使用互斥,就像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;
}
这是不完全正确的,因为实际的变换是更复杂,并使用递归锁,但它应该传达出点。
在Objective-C,一个@synchronized
块处理锁定和解锁(以及可能的例外)为您自动。 在运行时动态本质上产生与你同步的对象相关联的NSRecursiveLock。 这苹果文档解释了它的更多细节。 这就是为什么你不能从你的NSLock子看到日志消息 - 您同步的对象可以是任何东西,而不仅仅是一个NSLock。
基本上, @synchronized (...)
是一个方便的结构,它简化了你的代码。 最喜欢的简化的抽象,它相关的开销(认为它作为一个隐性成本),它是很好的意识到这一点,但无论如何使用这样的构造时原始性能可能不是最高目标。
其实
{
@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;
}
因为iOS版2.0中提供这个API,并采用进口...
#import <objc/objc-sync.h>
苹果执行@Synchronized是开源的,可以发现在这里 。 迈克灰写了两分关于这个主题真的很有趣的帖子:
- 锁,线程安全,和斯威夫特
- 让我们建立@Synchronized
概括地说其具有映射对象指针(利用其存储器地址作为密钥)的表pthread_mutex_t
锁,其锁定和解锁根据需要。