线程安全

一直不知道为什么线程会不安全,今天遇到了一种情况。

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);
        });

线程安全。

你可能感兴趣的:(线程安全)