簡體   English   中英

同步此多線程代碼(iOS / Cocoa)的正確方法是什么?

[英]What is the correct way to synchronize this multithreaded code (iOS/Cocoa)?

假設我有一個NSMutableArray對象( NSMutableArray 不是線程安全的),並且在包含此數組的對象上有這些方法(為清楚起見,這是一個簡化的示例):

- (void)addObject:(id)object {
    if (_objectsArray == nil) {
        _objectsArray = [NSMutableArray array];
    }

    [_objectsArray addObject:object];

    if (_thread == nil) {
        _thread = [[NSThread alloc] initWithTarget:self selector:@selector(__threadEntry:) object:nil];
        _thread.name = @"com.company.ThreadName";
        [_thread start];
    }
}

- (void)removeObject:(id)object {
    [_objectsArray removeObject:object];

    if (_objectsArray.count == 0) {
        _isRunning = NO;
    }
}

- (void)stopRendering {
    _isRunning = NO;
}

- (void)__threadEntry:(id)sender {
    // Set up CADisplayLink on current run loop.

    // "_isRunning" is declared as a "volatile BOOL"
    _isRunning = YES;
    while (_isRendering) {
        [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    // Thread cleanup.
}

- (void)__threadProc {
    @autoreleasepool {
        [_objectsArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            // Do work
        }];
    }
}

因此,基本上,我有一些方法可以從可變數組中添加/刪除對象,但是對數組中對象的處理是在另一個線程上執行的。 addObjectremoveObject都只能從主線程調用,而工作(在__threadProc )是在另一個線程上完成的。

實際上,此代碼不是線程安全的,因為可以在__threadProc進行枚舉時添加/刪除對象。 那么同步它的正確方法是什么?

我不確定鎖是否是正確的答案,因為鎖是否可以跨不同的方法工作? 例如,如果我在addObject方法中對[_objectsArray addObject:object]進行了鎖定/解鎖,而對__threadProc的工作進行了鎖定/解鎖,那么該工作是否可行(假設兩者都是同一個鎖定對象(例如NSLock )) ?

此外,與__threadProc完成工作的頻率相比,添加/刪除對象的頻率非常低。

假設我們正在Objective-C中實現線程安全隊列。 我們可以這樣開始:

@implementation ThreadSafeQueue
{
   NSMutableArray * _objectsArray;
   NSLock *_lock;
}

- (instancetype)init
{
    self = [super init];
     if (self) {
    _objectsArray = [NSMutableArray array];
    _lock = [[NSLock alloc] init];
 }
  return self;
}

- (void)push:(id)object
{
   [_lock lock];
   [_objectsArray addObject:object];
   [_lock unlock];
}

// Or using the @synchronized construct:

 @synchronized (self) {
    [_elements addObject:element];
  }
@end

上面的ThreadSafeQueue類具有一個init方法,該方法初始化兩個ivars:_objectsArray數組和NSLock。 它具有push:方法,該方法獲取鎖,將_object插入數組,然后釋放鎖。 許多線程可以同時調用push :,但是[_objectsArray addObject:object]行一次只能在一個線程上運行。 步驟可能如下所示:

 Thread A calls the push: method
 Thread B calls the push: method
 Thread B calls [_lock lock] - since nobody else is holding the lock, 
 Thread B acquires the lock
 Thread A calls [_lock lock] but the lock is held by Thread B so the method call doesn’t return - this pauses execution in thread A
 Thread B adds its objects to _objectsArray and calls [_lock unlock]. When this happens, Thread A’s [_lock lock] method returns and it goes on to insert its own object

我們可以使用@synchronized構造來更簡潔地實現這一點:

同步塊的作用與上述示例中的[_lock lock]和[_lock unlock]相同。 您可以將其視為對self的鎖定,就好像self是一個NSLock。 在運行{之前的{}之后的任何代碼之前先獲得一個鎖,並且在運行{}之后的任何代碼之前●釋放該鎖。 這真的很方便,因為這意味着您永遠不會忘記調用解鎖!

//或使用@synchronized構造:

 @synchronized (self) {
    [_elements addObject:element];
  }

您可以在任何Objective-C對象上@synchronize。 因此,在上面的示例中,我們也可以使用@synchronized(_elements)代替@synchronized(self),並且效果是相同的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM