美文网首页
iOS多线程初探

iOS多线程初探

作者: 雾霾下的天空 | 来源:发表于2018-12-28 14:41 被阅读6次

    最近做项目遇到消息处理的问题,涉及到消费与生产的多线程问题。而看到同事知其然不知其所以然的代码,想纠正发现自己的理解也不深入。

    不多废话,show me the code。
    首先是代码声明 与 初始化

    {
        dispatch_source_t produceTimer; //生产者定时器
        dispatch_source_t consumeTimer; //消费者定时器
    }
    @property (nonatomic, strong) dispatch_queue_t produceDataQueue;    //生产者队列
    @property (nonatomic, strong) dispatch_queue_t consumeDataQueue;    //消费者队列
    
    @property (nonatomic, strong) NSMutableArray *dataArray;    //数据 通常是网络数据
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.produceDataQueue = dispatch_queue_create("saveDataQueue", DISPATCH_QUEUE_SERIAL);
        self.consumeDataQueue = dispatch_queue_create("readDataQueue", DISPATCH_QUEUE_SERIAL);
        
        [self produceData];
        [self consumeData];
    }
    
    - (void)produceData {
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.produceDataQueue);
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(timer, ^{
            [self writeData];
        });
        dispatch_resume(timer);
        produceTimer = timer;
    }
    
    - (void)consumeData {
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.consumeDataQueue);
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(timer, ^{
            [self readData];
        });
        dispatch_resume(timer);
        consumeTimer = timer;
    }
    
    - (NSMutableArray *)dataArray {
        if (!_dataArray) {
            _dataArray = [NSMutableArray array];
        }
        return _dataArray;
    }
    

    开启两个0.1秒的定时器, 并且增加一定的随机性.

    - (void)writeData {
        int flag = arc4random() % 3;
        if (flag == 1) {
            return;
        }
        
        NSLog(@"beginWriteData");
        for (int i=0; i<10; i++) {
            [self.dataArray addObject:@(i)];
            NSLog(@"writeData:%d", i);
        }
        NSLog(@"endWriteData:%ld", self.dataArray.count);
    }
    
    - (void)readData {
        int flag = arc4random() % 10;
        if (flag == 1) {
            return;
        }
        
        NSLog(@"beginReadData:");
        for (int i=0; i<self.dataArray.count; i++) {
            NSLog(@"%@", [NSString stringWithFormat:@"dataArray[%d]:%@", i, self.dataArray[i]]);
        }
        [self.dataArray removeAllObjects];
        NSLog(@"endReadData:");
    }
    
    崩溃信息

    两个线程同时操作 dataArray, 在 saveData 方法进行add操作的时候, readData 方法进行了 removeAll 操作, 导致 add 操作的insertObject 越界崩溃.

    第一次尝试. 属性设置为 Atomic 无效.
    @property (nonatomic, strong) NSMutableArray *dataArray; //数据 通常是网络数据

    第二次尝试 @synchronized 属性
    只对 write 进行 synchronized

            @synchronized (self.dataArray) {
                [self writeData];
            }
    
    2018-12-21 21:18:34.253060+0800 test[23138:1268565] writeData:1
    2018-12-21 21:18:34.253092+0800 test[23138:1268566] dataArray[1]:1
    test(23138,0x700003a63000) malloc: *** error for object 0x600002016720: pointer being freed was not allocated
    test(23138,0x700003a63000) malloc: *** set a breakpoint in malloc_error_break to debug
    2018-12-21 21:18:34.269296+0800 test[23138:1268565] writeData:2
    

    对 write 与 read 都进行synchronized 加锁

            @synchronized (self.dataArray) {
                [self readData];
            }
    

    pass 有效

    synchronized 相关原理参考下面的 blog
    关于 @synchronized,这儿比你想知道的还要多

    相关文章

      网友评论

          本文标题:iOS多线程初探

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