发生读取时,Objective C 锁定写入操作
ObjectiveC locking write operation when read happens
我有一个 ObjC class (Writer),它有一些属性,它在主线程上写入这些属性。然后还有其他class(Reader)在主线程或后台线程上读取这些属性。
当reader从主线程读取时,它获得了 Writer class 中这些属性的确切值,但是当reader从后台线程读取时,显然没有保证reader 将获得相同的值。这是示例代码。
这里是 Writer class
- numberString 都是用逗号分隔的,例如。 1,1,1,1
- numberSum 是这些的总和,例如。 4
在Reader class:
我想确保 numberSum 确实是
numberString 变量。
// 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
这是演示代码,仅供示例使用。 reader 块中的两个 NSLog 语句在主线程中执行时将始终打印相同的内容,但在后台线程中它们有时会有所不同,因为在读取 numberString 后在 Reader 中读取 numberSum 时它有已由 Writer 中的主线程更新。
无论调用线程如何,我应该怎么做才能确保始终获得正确的值?
您需要的是并发调度队列和调度屏障功能的组合。只要您需要同时访问 numberString
和 numberSum
,就应该将其隐藏并提供一个方法来同时获取它们。像这样
@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
我有一个 ObjC class (Writer),它有一些属性,它在主线程上写入这些属性。然后还有其他class(Reader)在主线程或后台线程上读取这些属性。
当reader从主线程读取时,它获得了 Writer class 中这些属性的确切值,但是当reader从后台线程读取时,显然没有保证reader 将获得相同的值。这是示例代码。
这里是 Writer class
- numberString 都是用逗号分隔的,例如。 1,1,1,1
- numberSum 是这些的总和,例如。 4
在Reader class:
我想确保 numberSum 确实是 numberString 变量。
// 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
这是演示代码,仅供示例使用。 reader 块中的两个 NSLog 语句在主线程中执行时将始终打印相同的内容,但在后台线程中它们有时会有所不同,因为在读取 numberString 后在 Reader 中读取 numberSum 时它有已由 Writer 中的主线程更新。
无论调用线程如何,我应该怎么做才能确保始终获得正确的值?
您需要的是并发调度队列和调度屏障功能的组合。只要您需要同时访问 numberString
和 numberSum
,就应该将其隐藏并提供一个方法来同时获取它们。像这样
@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