web-dev-qa-db-ja.com

Objective-Cで@synchronizedをロック/ロック解除するにはどうすればよいですか?

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

Objective-C言語レベルの同期は、NSLockが行うように、mutexを使用します。意味的にはいくつかの小さな技術的な違いがありますが、それらを共通の(よりプリミティブな)エンティティの上に実装された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;
}

実際の変換はより複雑で、再帰ロックを使用するため、これは正確ではありませんが、ポイントを取得する必要があります。

311
Louis Gerbarg

Objective-Cでは、@synchronizedブロックがロックとロック解除(および可能な例外)を自動的に処理します。ランタイムは基本的に、同期しているオブジェクトに関連付けられているNSRecursiveLockを動的に生成します。 このAppleドキュメンテーション でさらに詳しく説明しています。 NSLockサブクラスからのログメッセージが表示されないのはこのためです。同期するオブジェクトは、NSLockだけでなく、何でもかまいません。

基本的に、@synchronized (...)はコードを合理化する便利な構造です。最も単純化された抽象化と同様に、オーバーヘッド(隠されたコストと考えてください)が関連付けられていることに注意してください。

40
Quinn Taylor

実は

{
  @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>
31
Dirk Theisen

Appleの@synchronizedの実装はオープンソースであり、 here にあります。マイク・アッシュは、このテーマに関する2つの非常に興味深い投稿を書いています。

簡単に言うと、オブジェクトポインター(キーとしてメモリアドレスを使用)をpthread_mutex_tロックにマップするテーブルがあり、必要に応じてロックおよびロック解除されます。

3
Raspu