这个GCD实现了getter setter线程安全并且比@synchronized更好吗? objc

时间:2015-03-17 07:16:25

标签: ios objective-c multithreading thread-safety grand-central-dispatch

@interface ViewController ()
@property (nonatomic, strong) NSString *someString;
@end

@implementation ViewController

@synthesize someString = _someString;

- (NSString *)someString {
    __block NSString *tmp;
    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        tmp = _someString;
    });
    return tmp;
}

- (void)setSomeString:(NSString *)someString {
    __block NSString *tmp;
    dispatch_barrier_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        tmp = someString;
    });
    _someString = tmp;
}
@end
有人说它比@synchronized方式更好,因为所有锁定都是在GCD中处理的。

2 个答案:

答案 0 :(得分:6)

首先,你的setter完全没有意义,使用默认的并发队列也可能不是你想要的。您的代码应该看起来更像:

@interface ViewController ()
@property (nonatomic, copy) NSString *someString;
@end

@implementation ViewController
{
    dispatch_queue_t _stateGuardQueue;
}

- (instancetype)init
{
    if (self = [super init])
    {
        _stateGuardQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

@synthesize someString = _someString;

- (NSString *)someString {
    __block NSString *tmp;
    dispatch_sync(_stateGuardQueue, ^{
        tmp = _someString;
    });
    return tmp;
}

- (void)setSomeString:(NSString *)someString {
    NSString* tmp = [someString copy];
    dispatch_barrier_async(_stateGuardQueue, ^{
        _someString = tmp;
    });
}

@end

我所做的改变:

  • 让setter实际在临界区内进行变异
  • 使用私有的每实例并发队列而不是全局默认并发队列;将障碍块提交到默认并发队列并不能达到您的预期。 (见docs
  • dispatch_barrier_sync更改为dispatch_barrier_async在同步等待setter块返回时没有任何意义,因为无法在当前线程上获得过时的读取。
  • 将属性更改为具有copy语义,这始终是值语义类型(NSString等)的良好实践。)在可以从多个并发读取属性的情况下,这一点尤为重要线程。

要知道的是,在孤立的情况下,这种模式不会提供比原子属性更多的“安全性”,所以你应该只使用那些(更少的代码等)。至于性能问题,是的,对于这种特殊用途,GCD肯定会胜过@synchronized。例如,它允许并发读取,其中@synchronized将序列化并发读取。没有测试,我希望原子属性能够胜过两者。这就是原子属性,并且通常以这种方式保护单个操作,很少是一个充分的并发策略。

答案 1 :(得分:0)

为什么不喜欢以下,使用异步方法:

- (NSString *)someString {
    __block NSString *tmp;
    dispatch_async(_stateGuardQueue, ^{
        tmp = _someString;
    });
    return tmp;
}