如何在Objective-C中锁定/解锁@synchronized?

时间:2009-07-31 23:16:19

标签: objective-c synchronization

@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];
}

5 个答案:

答案 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)

它只是将信号量与每个对象相关联,并使用它。