赞
踩
GCD中常用的栅栏函数,主要有两种
前面的任务执行完毕才会来到这里,但是同步栅栏函数会堵塞线程,影响后面的任务执行
前面的任务执行完毕才会来到这里
栅栏函数最直接的作用就是控制任务执行顺序,使同步执行。
- (void)demo2 {
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue2, ^{
sleep(2);
NSLog(@"异步任务");
});
dispatch_barrier_async(queue2, ^{
NSLog(@"栅栏任务");
});
NSLog(@"主线程任务");
}
打印结果
主线程任务
异步任务
栅栏任务
异步栅栏函数阻塞的是队列,而且必须是自定义的并发队列,不影响主线程任务的执行
- (void)demo2 {
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue2, ^{
sleep(2);
NSLog(@"异步任务");
});
dispatch_barrier_sync(queue2, ^{
NSLog(@"栅栏任务");
});
NSLog(@"主线程任务");
}
打印结果
异步任务
栅栏任务
主线程任务
dispatch_barrier_sync 它是同步,所以必须dispatch_barrier_sync^{ () }block 里面执行完,才执行后面
同步栅栏函数阻塞的是线程,且是主线程,会影响主线程其他任务的执行
- (void)demo2 {
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
NSMutableArray *mArray = [NSMutableArray array];
for (NSInteger i = 0; i < 5000; i++) {
dispatch_async(queue2, ^{
NSString *url = [NSString stringWithFormat:@"%ld.png",(long)i];
[mArray addObject:url];
});
}
}
运行崩溃
崩溃的堆栈中看到
崩溃之前调用了-[__NSArrayM insertObject:atIndex:]这个函数,我们再objc底层源码中去查看如下:
insertObject:底层源码
- (id)insertObject:anObject at:(unsigned)index
{
register id *this, *last, *prev;
if (! anObject) return nil;
if (index > numElements)
return nil;
if ((numElements + 1) > maxElements) {
volatile id *tempDataPtr;
/* we double the capacity, also a good size for malloc */
// 这里在数组超过一定的空间之后就进行了双倍的扩容
maxElements += maxElements + 1;
// 这里数组tempDataPtr 进行了realloc操作 所以在多个线程同时访问的时候就会出现问题
tempDataPtr = (id *) realloc (dataPtr, DATASIZE(maxElements));
dataPtr = (id*)tempDataPtr;
}
this = dataPtr + numElements;
prev = this - 1;
last = dataPtr + index;
while (this > last)
*this-- = *prev--;
*last = anObject;
numElements++;
return self;
}
- (id)addObject:anObject
{
return [self insertObject:anObject at:numElements];
}
这段就是可变数组添加数据时候底层实现,可以很清晰的看到,当数组的容量超过一定的maxElements的时候就会maxElements += maxElements + 1;,并且进行realloc重新创建了一个新的数组的操作,
在多线程的操作,如果数组添加的元素太多就会出现给旧数组添加元素的时候,旧的数组其实已经被替代的情况,这样就出现了崩溃。
数组元素比较小
可以看到并不会崩溃!!!
异步并发执行addObject的时候会造成数组指针赋值错误的崩溃情况,当数组的容量maxElements固定之后就不会重新realloc ,就避免了同时访问数组失败的问题,
互斥锁@synchronized 也是可以的
- (void)demo2 {
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
NSMutableArray *mArray = [NSMutableArray array];
for (NSInteger i = 0; i < 10000; i++) {
dispatch_async(queue2, ^{
NSString *url = [NSString stringWithFormat:@"%ld.png",(long)i];
dispatch_barrier_sync(queue2, ^{
[mArray addObject:url];
});
});
}
}
#ifdef __BLOCKS__
void
dispatch_barrier_async(dispatch_queue_t dq, dispatch_block_t work)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
uintptr_t dc_flags = DC_FLAG_CONSUME | DC_FLAG_BARRIER;
dispatch_qos_t qos;
qos = _dispatch_continuation_init(dc, dq
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。