在下面的代码中,我们有一个可变数组,它由两个并发队列进行突变。由于并发队列不是线程安全的,因此理想情况下此代码应该崩溃,但这会在没有任何异常或崩溃的情况下执行。
请帮助我理解这种行为。任何帮助将不胜感激: - )
@interface ViewController ()
@property(nonatomic, strong) NSMutableArray *arr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.arr = [NSMutableArray new];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 20000; i++) {
[weakSelf.arr addObject:[NSNumber numberWithInt:i]];
NSLog(@"Added %@", [weakSelf.arr lastObject]);
}
NSLog(@"Final count %ld", [self.arr count]);
});
[self performSelector:@selector(removeObjects) withObject:nil afterDelay:0.1];
}
-(void)removeObjects{
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 1000; i++) {
if (weakSelf.arr.count > 1) {
[weakSelf.arr removeObjectAtIndex:0];
}
NSLog(@"Remove object");
}
});
}
@end
答案 0 :(得分:0)
同时访问一个资源并不意味着崩溃得到保证。这与&#34;幸运无关&#34;无关。也许你的代码会在没有崩溃的情况下系统地运行。
此外,&#34;不是线程安全的&#34;并不意味着&#34;会崩溃&#34;。任何故障都可能发生。
答案 1 :(得分:0)
对NSMutableArray
的并发访问权限明确导致崩溃,但可能导致数据损坏,从而导致您的应用因数据无效而崩溃。
考虑一下这个稍微修改过的代码版本:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
for (int i = 0; i < 20000; i++) {
NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]);
[weakSelf.arr insertObject:[NSNumber numberWithInt:i] atIndex:randomIndex];
NSLog(@"Added %@", weakSelf.arr[randomIndex]);
}
NSLog(@"Final count %ld", [self.arr count]);
});
[self performSelector:@selector(removeObjects) withObject:nil afterDelay:0.1];
}
-(void)removeObjects{
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 0; i < 1000; i++) {
if (weakSelf.arr.count > 1) {
NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]);
[weakSelf.arr removeObjectAtIndex:randomIndex];
}
NSLog(@"Remove object");
}
});
}
每次运行时,最终计数值都会略有不同。
如果您添加@synchronized
以使阵列访问线程安全,那么您总是得到最终计数为19000
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
for (int i = 0; i < 20000; i++) {
@synchronized (self.arr) {
NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]);
[weakSelf.arr insertObject:[NSNumber numberWithInt:i] atIndex:randomIndex];
NSLog(@"Added %@", weakSelf.arr[randomIndex]);
}
}
NSLog(@"Final count %ld", [self.arr count]);
});
[self performSelector:@selector(removeObjects) withObject:nil afterDelay:0.1];
}
-(void)removeObjects{
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
for (int i = 0; i < 1000; i++) {
if (weakSelf.arr.count > 1) {
@synchronized (self.arr) {
NSUInteger randomIndex = arc4random_uniform([weakSelf.arr count]);
[weakSelf.arr removeObjectAtIndex:randomIndex];
}
}
NSLog(@"Remove object");
}
});
}
在使用快速枚举时对数组进行变换会导致崩溃,但在这种情况下,变异甚至不必来自另一个线程;简单地在枚举循环中改变数组将导致崩溃。