ios - 在 iOS 中创建一个类 "thread safe"

标签 ios objective-c thread-safety

我正在阅读 Apple docs围绕线程安全,我并不完全清楚什么(在实践中)真正构成了一个线程安全的类。为了帮助更好地理解这一点,需要对以下类做些什么才能使其成为线程安全的(以及为什么)?

#import "UnsafeQueue.h"

@interface UnsafeQueue()

@property (strong, nonatomic) NSMutableArray *data;

@end

@implementation UnsafeQueue

- (id)peek {
    return [self.data firstObject];
}

- (NSUInteger)length {
    return [self.data count];
}

- (void)enqueue:(id)datum {
    [self.data addObject:datum];
}

// other methods omitted...

@end

是否会简单地创建一个 ivar NSLock,然后锁定/解锁周围 所有 与底层 NSMutableArray 的交互?

仅要求数组计数的长度方法是否也需要执行此操作?

最佳答案

使类线程安全的最简单和最好的方法是使其不可变。那么你不必处理任何这些。它只是工作。确实值得花时间考虑是否需要在多线程上实现可变性。

但是,如果不可变类给您的设计带来了重大问题,那么实现它的最佳方法通常是使用 GCD 而不是锁。 GCD 的开销要低得多,一般来说更容易正确。

在这种特殊情况下,我将按照以下方式实现它(未经测试,我已经在 Swift 中工作了一段时间,所以如果我省略了分号,请原谅我):

#import "SafeQueue.h"

@interface SafeQueue()

@property (strong, nonatomic) NSMutableArray *data;
@property (strong, nonatomic) dispatch_queue_t dataQueue;

@end

@implementation SafeQueue

- (instancetype)init {
    if (self = [super init]) {
        _dataQueue = dispatch_queue_create("SafeQueue.data", DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

- (id)peek {
    __block id result = nil;
    dispatch_sync(self.dataQueue, ^{ result = [self.data firstObject] });
    return result;
}

- (NSUInteger)length {
    __block NSUInteger result = 0;
    dispatch_sync(self.dataQueue, ^{ result = [self.data count] });
    return result;
}

- (void)enqueue:(id)datum {
    dispatch_barrier_async(self.dataQueue, ^{ [self.data addObject:datum] });
}

// other methods omitted...

@end

请注意对所有读取器使用 dispatch_sync,对所有写入器使用 dispatch_barrier_async。这就是通过允许并行读取器和独占写入器来将开销降至最低的方法。如果没有争用(这是正常情况),dispatch_sync 的开销比锁(NSLock@synchronized 甚至pthreads 锁)。

参见 Migrating Away from Threads从 Apple 获得更多关于如何更好地处理 Cocoa 并发的建议。

关于ios - 在 iOS 中创建一个类 "thread safe",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28005734/

相关文章:

ios - 不确定公共(public)或私有(private)变量声明和自委托(delegate)?

python - 程序退出结束时 pyobjc 和 wx 崩溃

iphone - Xcode 中的 TDD 工作流 - 在进行红绿重构时如何为 "quick fix"?

ios - 串行队列比同步块(synchronized block)更快吗?

ios - 无法通过使用 HttpClient 在 ionic 中设置授权 header 来发送 Bearer token

ios - 相机图像选择器控件 - iOS7 中的自动旋转

iphone - iOS 中带有图片的 XML Gridview

ios - 由于配置文件处于非事件状态,Testflight 错误无法安装 <appname> WWDR 错误

java - 在 Brian Goetz 的 Java Concurrency In Practice 中,为什么 Memoizer 类没有使用 @ThreadSafe 注释?

java - 非最终实例的线程安全延迟初始化