1. ホーム
  2. オブジェクティブC

[解決済み】Objective-Cで@synchronizedのロック/アンロックはどのように行われるのですか?

2022-04-18 02:43:20

質問

synchronizedは相互排他を実現するために"lock"と"unlock"を使用しないのですか?その場合、lock/unlockはどのように行うのでしょうか?

次のプログラムの出力は "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の言語レベルの同期にはmutexが使われており、ちょうど NSLock があります。意味的には細かい技術的な違いがありますが、基本的には共通の(より原始的な)実体の上に実装された2つの別々のインターフェースと考えるのが正しいでしょう。

特に 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;
}

実際の変換はもっと複雑で、再帰的なロックを使用するので、これは正確ではありませんが、ポイントは伝わると思います。