iOS多线程初探

2018-12-28  本文已影响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,这儿比你想知道的还要多

上一篇下一篇

猜你喜欢

热点阅读