美文网首页
偶现线程读写问题导致的bugly崩溃验证和修复

偶现线程读写问题导致的bugly崩溃验证和修复

作者: wg689 | 来源:发表于2021-03-09 17:04 被阅读0次

    偶现问题复现 ,for 循环10万次增加偶现概率

    - (void)viewDidLoad {
        [super viewDidLoad];
        dispatch_queue_t concurrentQueue = dispatch_queue_create("tianyao", DISPATCH_QUEUE_CONCURRENT);
        
        
        dispatch_async(concurrentQueue, ^{
            for(int i = 0;i < 100000;i++){
                [self writeTest];
                NSLog(@"%d 线程:%@", i, [NSThread currentThread]);
            }
        });
        
    //    dispatch_queue_t concurrentQueue2 = dispatch_queue_create("tianyao2", DISPATCH_QUEUE_CONCURRENT);
    
        dispatch_async(concurrentQueue, ^{
            for(int i = 0;i < 100000;i++){
                [self readTest];
                NSLog(@"%d 线程:%@", i, [NSThread currentThread]);
                
            }
        });
          
    }
    
    
    
    - (void)writeTest{
        DYTestManager *manager = [DYTestManager shareInstant];
        NSArray *arr = @[@"1",@"2",@"3",@"4",@"5"];
        NSMutableArray *arrM  = [NSMutableArray arrayWithArray:arr];
        [arrM addObject:@(random())];
        manager.dayRankList = arrM;
        NSLog(@"写入的数组%@",arrM);
    }
    
    
    - (void)readTest{
        DYTestManager *manager = [DYTestManager shareInstant];
        NSArray *arr =  manager.dayRankList;
        NSLog(@"读出的数组");
    }
    
    

    尝试5次, 每次分别给予10万次读和写 , 出现4次crash


    问题复现

    dayrankList变量存在同时写入的情况, 这个情况是极低的概率出现, 所以会出现偶现的crash

    问题修复

    //
    //  ViewController.m
    //  writeread
    //
    //  Created by wanggang on 2021/3/9.
    //
    
    #import "ViewController.h"
    #import "DYTestManager.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        dispatch_queue_t concurrentQueue = dispatch_queue_create("tianyao", DISPATCH_QUEUE_CONCURRENT);
        
        
        dispatch_async(concurrentQueue, ^{
            for(int i = 0;i < 100000;i++){
                [self writeTest];
                NSLog(@"%d 线程:%@", i, [NSThread currentThread]);
            }
        });
        
    //    dispatch_queue_t concurrentQueue2 = dispatch_queue_create("tianyao2", DISPATCH_QUEUE_CONCURRENT);
    
        dispatch_async(concurrentQueue, ^{
            for(int i = 0;i < 100000;i++){
                [self readTest];
                NSLog(@"%d 线程:%@", i, [NSThread currentThread]);
                
            }
        });
          
    }
    
    
    
    - (void)writeTest{
        DYTestManager *manager = [DYTestManager shareInstant];
        NSArray *arr = @[@"1",@"2",@"3",@"4",@"5"];
        NSMutableArray *arrM  = [NSMutableArray arrayWithArray:arr];
        [arrM addObject:@(random())];
        
        // 写操作
        dispatch_queue_t queue = manager.readWriteQueue;
        dispatch_barrier_async(queue, ^{
            // Write action.
            manager.dayRankList = arrM;
            NSLog(@"内部写 线程:%@",  [NSThread currentThread]);
    
        });
        NSLog(@"写入的数组%@",arrM);
    }
    
    
    - (void)readTest{
        DYTestManager *manager = [DYTestManager shareInstant];
        // 继续执行读操作
        dispatch_queue_t queue = manager.readWriteQueue;
        dispatch_sync(queue, ^{
            // Read action3.
            NSArray *arr =  manager.dayRankList;
            NSLog(@"内部读 线程:%@",  [NSThread currentThread]);
        });
        
    
    }
    
    
    
    @end
    
    

    读写不同线程不会crash

    image.png

    问题总结

    • 同时读写都在一个线程 同步不会crash
    • 读写在不同的线程, 偶现的crash , 非必现 ,demo验证10万分之1左右
    • 读写在不同的线程通过增加锁验证可以解决
      增加锁的主要代码如下:
    // 创建一个并行队列
    dispatch_queue_t queue = dispatch_queue_create("LLDebugtool.com", DISPATCH_QUEUE_CONCURRENT);
    
    // 执行一些读操作
    dispatch_sync(queue, ^{
        // Read action1.
    });
    
    dispatch_sync(queue, ^{
        // Read action2.
    });
    
    ...
    // 写操作
    dispatch_barrier_async(queue, ^{
        // Write action.
    });
    
    // 继续执行读操作
    dispatch_sync(queue, ^{
        // Read action3.
    });
    
    dispatch_sync(queue, ^{
        // Read action4.
    });
    
    
    

    线程加读写锁之后的特点

    • 同一时间,只能有一个线程进行写的操作。
    • 同一时间,允许有多个线程进行读的操作。
    • 同一时间,不允许既有写的操作,又有读的操作。

    参考文献

    https://juejin.cn/post/6844903966099128328

    相关文章

      网友评论

          本文标题:偶现线程读写问题导致的bugly崩溃验证和修复

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