is this GCD implemented getter setter thread safe and work better than @synchronized? objc

混江龙づ霸主 提交于 2019-12-05 02:54:22

问题


@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

some said it's better than @synchronized way because all the locking is handled down in GCD.


回答1:


First off, your setter makes no sense at all, and using the default concurrent queue is also probably not what you want. Your code should probably look more like:

@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

The changes I made:

  • Make the setter actually do the mutation inside the critical section
  • Use a private, per-instance concurrent queue instead of the global default concurrent queue; Submitting barrier blocks to default concurrent queues doesn't do what you think it does. (See the docs)
  • Change dispatch_barrier_sync to dispatch_barrier_async there's no point at all in waiting synchronously for the setter block to return, as there's no way to get a stale read on the current thread.
  • Change the property to have copy semantics, which is always good practice with value-semantic types (NSString, etc.) This is especially important in cases where the property might be read concurrently from multiple threads.

The thing to know is that, in isolation, this pattern provides no more "safety" than atomic properties, so you should arguably just use those (less code, etc). As to the performance question, yes, for this particular use, GCD will certainly out-perform @synchronized. For one, it allows concurrent reads, where @synchronized will serialize concurrent reads. Without testing, I would expect atomic properties to out-perform both. That said atomic properties, and protecting single operations in this way in general, are rarely an adequate concurrency strategy.




回答2:


why not like below ,using async method:

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


来源:https://stackoverflow.com/questions/29093312/is-this-gcd-implemented-getter-setter-thread-safe-and-work-better-than-synchron

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!