@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];
}
答案 0 :(得分:311)
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;
}
这不完全正确,因为实际的转换更复杂并且使用了递归锁,但它应该得到重点。
答案 1 :(得分:40)
在Objective-C中,@synchronized
块会自动为您处理锁定和解锁(以及可能的异常)。运行时动态地生成一个NSRecursiveLock,它与您正在同步的对象相关联。 This Apple documentation更详细地解释了它。这就是为什么你没有看到来自你的NSLock子类的日志消息 - 你同步的对象可以是任何东西,而不仅仅是一个NSLock。
基本上,@synchronized (...)
是简化代码的便捷构造。像大多数简化的抽象一样,它具有相关的开销(将其视为隐藏成本),并且很好地意识到这一点,但是无论如何使用这样的结构时,原始性能可能不是最高目标。
答案 2 :(得分:31)
实际上
{
@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>
答案 3 :(得分:3)
Apple的@synchronized实现是开源的,可以找到here。 Mike Ash写了两篇关于这个主题的非常有趣的帖子:
简而言之,它有一个表将对象指针(使用其内存地址作为键)映射到pthread_mutex_t
锁,这些锁根据需要锁定和解锁。
答案 4 :(得分:-3)
它只是将信号量与每个对象相关联,并使用它。