it-swarm-vi.tech

Làm thế nào để khóa / mở khóa không đồng bộ trong Objective-C?

@Synyncized không sử dụng "khóa" và "mở khóa" để đạt được loại trừ lẫn nhau? Làm thế nào để nó khóa/mở khóa sau đó?

Đầu ra của chương trình sau chỉ là "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

Đồng bộ hóa mức ngôn ngữ Objective-C sử dụng mutex, giống như NSLock. Về mặt ngữ nghĩa có một số khác biệt kỹ thuật nhỏ, nhưng về cơ bản là chính xác khi nghĩ về chúng như hai giao diện riêng biệt được triển khai trên một thực thể chung (nguyên thủy hơn).

Đặc biệt với NSLock bạn có một khóa rõ ràng trong khi với @synchronized bạn có một khóa ẩn được liên kết với đối tượng bạn đang sử dụng để đồng bộ hóa. Lợi ích của việc khóa cấp độ ngôn ngữ là trình biên dịch hiểu nó để nó có thể xử lý các vấn đề phạm vi, nhưng về mặt cơ bản thì chúng hoạt động giống nhau.

Bạn có thể nghĩ về @synchronized như một trình biên dịch viết lại:

- (NSString *)myString {
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

được chuyển thành:

- (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;
}

Điều đó không chính xác bởi vì biến đổi thực tế phức tạp hơn và sử dụng các khóa đệ quy, nhưng nó sẽ có được điểm.

311
Louis Gerbarg

Trong Objective-C, khối @synchronized tự động khóa và mở khóa (cũng như các ngoại lệ có thể) cho bạn. Thời gian chạy về cơ bản tạo ra NSRecursiveLock được liên kết với đối tượng bạn đang đồng bộ hóa. Tài liệu này của Apple giải thích chi tiết hơn. Đây là lý do tại sao bạn không thấy các thông điệp tường trình từ lớp con NSLock của bạn - đối tượng bạn đồng bộ hóa có thể là bất cứ thứ gì, không chỉ là NSLock.

Về cơ bản, @synchronized (...) là một cấu trúc tiện lợi giúp sắp xếp hợp lý mã của bạn. Giống như hầu hết các khái niệm trừu tượng hóa, nó có liên quan đến chi phí (nghĩ về nó như một chi phí ẩn) và thật tốt khi biết điều đó, nhưng hiệu suất thô có lẽ không phải là mục tiêu tối cao khi sử dụng các cấu trúc như vậy.

40
Quinn Taylor

Thực ra

{
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

biến đổi trực tiếp thành:

// needs #import <objc/objc-sync.h>
{
  objc_sync_enter(self)
    id retVal = [[myString retain] autorelease];
  objc_sync_exit(self);
  return retVal;
}

API này có sẵn từ iOS 2.0 và được nhập bằng ...

#import <objc/objc-sync.h>
31
Dirk Theisen

Việc triển khai @synyncized của Apple là nguồn mở và có thể tìm thấy tại đây . Mike ash đã viết hai bài thực sự thú vị về chủ đề này:

Tóm lại, nó có một bảng ánh xạ các con trỏ đối tượng (sử dụng địa chỉ bộ nhớ của chúng làm khóa) thành các khóa pthread_mutex_t, được khóa và mở khóa khi cần.

3
Raspu