最近做项目遇到消息处理的问题,涉及到消费与生产的多线程问题。而看到同事知其然不知其所以然的代码,想纠正发现自己的理解也不深入。
不多废话,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,这儿比你想知道的还要多
网友评论