美文网首页
线程安全

线程安全

作者: xiari1991 | 来源:发表于2018-02-07 17:01 被阅读9次

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

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

    线程安全。

    相关文章

      网友评论

          本文标题:线程安全

          本文链接:https://www.haomeiwen.com/subject/etlazxtx.html