一直不知道为什么线程会不安全,今天遇到了一种情况。
dispatch_queue_t queue = dispatch_queue_create("qcdSafe.test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i =1000000; i< 2000000; i++) {
if (self.arr.count < 900000) {
[self.arr addObject:@(i)];
}
}
});
dispatch_async(queue, ^{
for (int i =0; i< 1000000; i++) {
if (self.arr.count < 900000) {
[self.arr addObject:@(i)];
}
}
});
多线程同时操作数组会发生闪退。
可以这样理解:如果修改数据发生在 同一个时刻,那么程序就不知改怎么处理数据了。这时会发生闪退。
而我们不单单要考虑是否发生闪退,还有考虑这个数组的大小是不是会超过900000。其实会超过的,这就是线程不安全的。
为什么要线程安全:比如我服务器有一个文件,10000个如何这个时候同时去修改这个文件,那么最终会怎么样呢?服务器也不知道,所以可能会闪退(ios nsfilemanager 是线程安全的,这里只是举例)。
那么怎么保证数组操作线程安全。我们讨论下NSLock
下面有三种方式,依次讨论
NSLock *lock = [[NSLock alloc] init];
self.arr = [NSMutableArray array];
dispatch_queue_t queue = dispatch_queue_create("qcdSafe.test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
int j = 0;
[lock lock];
for (int i =1000000; i< 2000000; i++) {
if (self.arr.count < 900000) {
[self.arr addObject:@(i)];
j++;
}
}
[lock unlock];
NSLog(@"count:%zd j=%d",self.arr.count, j);
});
dispatch_async(queue, ^{
int w = 0;
[lock lock];
for (int i =0; i< 1000000; i++) {
if (self.arr.count < 900000) {
[self.arr addObject:@(i)];
w++;
}
}
[lock unlock];
NSLog(@"count:%zd w=%d",self.arr.count, w);
});
这种方式可以实现线程安全,但是添加数据只是在第一个线程中执行,第二个线程不会执行。因为lock会阻塞第二个线程,第一个线程lock时,第二个线程lock无效。只有当unlock时第二个线程才会执行,但数组的容量已经达到上限了。
NSLock *lock = [[NSLock alloc] init];
self.arr = [NSMutableArray array];
dispatch_queue_t queue = dispatch_queue_create("qcdSafe.test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i =0; i< 1000000; i++) {
if (self.arr.count < 900000) {
[lock lock];
[self.arr addObject:@(i)];
[lock unlock];
}
}
NSLog(@"count:%zd",self.arr.count);
});
dispatch_async(queue, ^{
for (int i = 1000000; i< 2000000; i++) {
if (self.arr.count < 900000) {
[lock lock];
[self.arr addObject:@(i)];
[lock unlock];
}
// NSLog(@"2");
}
NSLog(@"count:%zd",self.arr.count);
});
无法达到线程安全,数组容量可能超过900000。因为当两个线程同时到lock的时候,加入这个时候容量已经达到了900000-1.未阻塞的线程会添加一个元素到数组,unlock后,另一个线程还是会添加一个元素到数组中。
NSLock *lock = [[NSLock alloc] init];
self.arr = [NSMutableArray array];
dispatch_queue_t queue = dispatch_queue_create("qcdSafe.test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
int i, w;
w = 0;
for (i = 0; i< 1000000; i++) {
[lock lock];
if (self.arr.count < 900000) {
[self.arr addObject:@(i)];
w++;
}
[lock unlock];
}
NSLog(@"count:%zd, w = %d",self.arr.count, w);
});
dispatch_async(queue, ^{
int i,j;
j = 0;
for (i = 1000000; i< 2000000; i++) {
[lock lock];
if (self.arr.count < 900000) {
[self.arr addObject:@(i)];
j++;
}
[lock unlock];
}
NSLog(@"count:%zd, j = %d",self.arr.count, j);
});
线程安全。
网友评论