objective-c - 发生读取时,Objective C 锁定写入操作

标签 objective-c multithreading locking grand-central-dispatch race-condition

我有一个 ObjC 类(Writer),它有一些属性,它在主线程上写入这些属性。然后还有其他类(Reader)在主线程或后台线程读取这些属性。

当 reader 从主线程读取时,它会获得 Writer 类中这些属性所持有的确切值,但是当 reader 从后台线程读取时,显然无法保证 reader 会获得相同的值。这是示例代码。

在 Writer 类中

  • numberString 都是用逗号分隔的,例如。 1,1,1,1
  • numberSum 是这些的总和,例如。 4

在 Reader 类中:

我想确保 numberSum 确实是所有 1 的总和 数字字符串变量。

// Writer Class
@interface Writer : NSObject
@property (nonatomic,strong) NSString* numberString;
@property (nonatomic,assign) NSUInteger numberSum;
@end

@implementation Writer

-(instancetype)init {
    if (self = [super init]){
        self.numberString = @"1";
        self.numberSum = 1;

        self.timer = [NSTimer timerWithTimeInterval:0.1f target:self selector:@selector(writeToVariables:) userInfo:nil repeats:YES];
        [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    }

    return self;
}

- (void)writeToVariables:(NSTimer *)timer {
    self.numberString = [self.numberString stringByAppendingString:@",1"];    
    self.numberSum += 1;
}

// Reader Class
@interface Reader ()
@property (nonatomic,strong) Writer* writer;
@end

@implementation Reader

-(instancetype)init {
        if (self = [super init]){
            self.writer = [Writer new];
        }
        return self;
    }

-(void) getVariablesOnBackground:(BOOL)background {

    void (^readerBlock)() = ^{

        NSString* numberStr = self.writer.numberString;

        // Introduce delay So background thread get time to update numberSum
        int i=0;
        while (i < 10000000) {
            i += 1;
        }

        NSUInteger numberSum = self.writer.numberSum;

        NSArray *onesArray = [numberStr componentsSeparatedByString:@","];
        NSLog(@"%lu",(unsigned long)onesArray.count);
        NSLog(@"%lu",(unsigned long)numberSum);
    };

    // If background then dispatch on default queue else just call the block
    if (background) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),readerBlock);
    }
    else {
        readerBlock();
    }
}
@end

这是演示代码,仅供示例使用。 readerBlock 中的两个 NSLog 语句在主线程中执行时将始终打印相同的内容,但在后台线程中它们有时会有所不同,因为在读取 numberString 后在 Reader 中读取 numberSum 时,它已被 Writer 中的主线程更新。

无论调用线程如何,我应该怎么做才能确保始终获得正确的值?

最佳答案

您需要的是并发调度队列和调度屏障功能的组合。只要您需要同时访问 numberStringnumberSum,就应该隐藏它并提供一个方法来同时获取它们。像这样

@interface Writer : NSObject {
    NSString* numberString;
    NSUInteger numberSum;

    dispatch_queue_t accessQueue;
}

- (NSDicionary*) readStringAndSum;
@end

@implementation Writer

- (instancetype) init {
    ...
    accessQueue = dispatch_queue_create("Access queue", DISPATCH_QUEUE_CONCURRENT);
    ...
}

- (void)writeToVariables:(NSTimer *)timer {

     dispatch_barrier_async(accessQueue, ^{
           numberString = [self.numberString stringByAppendingString:@",1"];    
           numberSum += 1;
      });

}


- (NSDicionary*) readStringAndSum; {
    __block NSDictionary* response;
    dispatch_sync(accessQueue ^{
        response = @{@"Sum" : [NSNumber numberWithUnsignedInteger: numberSum],
                     @"String" : [numberString copy];
                     }
    });

    return response;
}

@end

关于objective-c - 发生读取时,Objective C 锁定写入操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36616013/

相关文章:

ios - 自定义 UITableViewCell 圆角、padding、bgImage

multithreading - 功能语言中的并行性

search - 在 Elasticsearch 中让读取优先于写入

ios - UIBarButtonItem选择到下一个ViewController

ios - Swift 等效于静态 Objective-C 表达式

ios - 如何将源代码编译的 LLVM 与 Xcode 集成?

c - 了解发布顺序并在 C11 中同步

java - java中如何知道锁的信息?

c - 多进程无锁

sql - Oracle 选择更新行为