iOS-GCD

2021-02-18 09:28:21 浏览数 (1)

sync同步函数serial串行队列:不会开启线程,在当前线程执行任务,会产生堵塞

sync同步函数Concurrent并发队列:不会开启线程,任务一个接着一个,不会产生堵塞

async异步函数serial串行队列:开启线程一条新线程,任务一个接着一个

async异步函数Concurrent并发队列:开启线程,在当前线程执行任务,任务异步执行,没有顺序与cpu调度有关

同步:等待 1 串行:等待 1

主队列:专门用来在线程上调度任务的串行队列,不会开启线程,如果当前主线程有任务正在执行那么主队列的任务都不会被调度

全局队列:一个并发队列,且不能被栅栏函数作用,在使用多线程开发时,如果没有特殊需求,执行异步任务,默认使用全局队列

注释:DISPATH_QUEUE_WIDTH_FULL 0x1000ull

dispath_async(queue_t dq,block_t work){

1.申请空间 continuation

2.初始化init

dispath_continuation_init(dc,dq,work,0,dc_flags){

dc:申请的空间

dq:当前队列

work:任务

flags:标识

dispatch_function_t func = dispatch_Block_invoke(work)->dispatch_call_block_and_release(ctxt)

dc->dc_ctxt = ctxt (dc内的属性是alloc出来的)

dc->dc_func = f

qos= init_f(dc,dqu,ctxt,func,flags,dc_flags)

dispatch_continuation_async(dq,dc,qos,dc->dc_flags)

pop_inline-(dispatch_object_t dou )

}

GCD-单例

单例dispatch_once(dispatch_once_t *val ,ctxt,func){

dispatch_once_gate_t l=val;

1.v = os_atomic_load(&l->dgo_once,acquire)

2.if v==DLOCK_ONCE_DONE ->return

tryenter(l){加锁

3.os_atomic_cmpxchg(&l->dog_once,DLOCK_ONCE_UNLOCKED,lock_value_for_self,relaxed)

4.dispatch_once_callout(l,ctxt,func){gate_broadcast(l) 对已经调用的单例l进行广播}

}

5.broadcast(dispatch_once_gate_t l){

6.dispatch_lock value_self = _dispatch_lock_value_for_self();上一步比较cmp操作用到的参数,作用是修改v值,使下次再无法再次调用单例

7.v = dispatch_once_mark_done(l) //单例作用已完成 标记mark .v返回给os_atomic_load

{

8.return os_atomic_xchg(&dgo->dgo_once,DLOCK_ONCE_DONE,release)这个就是V返回给2

}

}

return once_wait(l)

}

GCD-栅栏函数(barrier)

dispatch_barrier_async(异步) 阻塞队列

dispatch_barrier_sync(同步) 阻塞线程

注释:栅栏函数只能传入一个自己创建的并发队列

GCD-同步函数

dispatch_sync_f_inline(dq,ctxt,func,dc_flags)

dq->dq_width==1 return _dispatch_barrier_sync_f(dq,ctxt,func,dc_flags)

dispatch_sync_function_invoke_inlie(dq,ctxt,func)

thread_frame dtf

push(&dtf,dq)

client_callout(ctxt,func) //block函数

pop(&dtf)

return _dispatch_lane_barrier_complete(dq)//释放

os_atomic_rww_loop_give_up 护犊子操作

GCD-死锁

dispatch_sync_f_slow

lock_by(lock_value,tid)

return (lock_value ^ tid)&DLOCK_OWNER_MASK == 0 //异或操作 相同=0 不同=1

判断当前队列与正在执行的队列是否相同 返回一个状态值

dq_state_drain_lock_by(dq_state,dispatch_sync_context_t dsc->dsc_waiter)

DISPATCH_CLIENT_CRASH(dq_state){

"dispatch_sync called on queue already owned by current thread"

}

GCD-调度组

搭配使用(实际上就是同步效果)

dispatch_group_async 进组任务

dispatch_group_create{

dg=alloc(group,sizeof(groups))

dg->do_next=LISTLESS

dg->do_target=default_queue

return dg

}

dispatch_group_enter{

old_bits=os_atomic_sub_orig2o(dg,dg_bits,GROUP_VALUE,acquire)

old_value=old_bits&MASK

如果old_value==0 retain(dg)

如果old_value==VALUE_MAX(CRASH"Too many nested calls to dispatch_group_enter")

}

dispatch_group_notify(监听调度组)只保证enter 和 leave 成对存在(dispatch_group_t dg,dq,dsn){

如果old_state==0 os_atomic_rmw_loop_give_up &return dispatch_group_weak苏醒

异步函数push pop invoke 等等

}

dispatch_group_leave差不多的操作{

new_state,old_state = os_atomic_add_orig2o(dg,dg_state,VALUE,release)

os_atomic_rmw_loop_give_up &return dispatch_group_weak苏醒

if old_value==0 ("Unbalanced call to dispatch leave")

}

GCD-信号量

dispatch_semphore_create(n) 控制GCD最大并发数

n=1 同步

n>=2 异步

dispatch_semphore_signal(dispatch_semaphore_t dsema){

os_atomic_inc2o(dsema,dsema_value,release)

add(dsema->dsema_value,1,m,add)

}

if value>0 return

or return signal_slow(dsema)长等待

总而言之:

1.create创建信号量

2.wait等待 os_atomic_des2o(dsema,dsema_value,release){

des(dsema->dsema_value,1,m,des)

if value >=0 return

}

3.释放

dispatch_semaphore_wait_slow(dsema,timeout)

GCD-source

create 创建源

set_event_handler 设置事件回调

merge_data 事件数据

get_data

resume 继续

suspend 挂起

GCD-synchronized

synchronized{

1.objc_sync_enter

2.objc_sync_exit

}

Lv1 源码层:

enter{

SyncData *data=id2data(obj,Acquired)

data->mutex.lock()

}

exit{

OBJC_Sync_success

Bool ok=data->mutex.unlock()

}

Lv2 :

typedef struct alignas(CacheLineSize)SyncData{

struct SyncData* nextData;下一个节点 链表结构

recursive_mutex_t mutex 定义一个递归锁

threadCount //计算有多少个线程正在使用这个block

}

id2Data{

tls->kvc 暂存空间,检查每个线程的单入口类匹配当前对象

bool fastcacheOccupied=No;

SyncData *data=tls_get_direct 拿到Key

if (data){

fastcacheOccupied=Yes

又一岑判断当前对象是否为key所绑定的对象

if data->objcet==object{

lockCount 记录有多少把锁,锁住了这个对象

lockCount=tls_get_direct(SYNC_COUNT_KEY)

switch(Acquired,Release)

tls_set_direct(COUNT_KEY,lockCount)

result->nextData =*listp 如果当前对象数据有下层依赖,切换成下一个节点

*listp = result

lockp.lock

{

SyncData *p

SyncData firstUnused = NULL;

for (p=*listp;p!=NULL;p=p->nextData){

且判断是否有下一个节点,如果没有break,还有继续循环

循环访问p->nextData 访问尾节点

result = p 结果赋值

OSAutomicIncrement32Barrier(&result->threadCount)

调用OS底层(取到线程数量地址)

}

Release check 没有正确的数据关联到这个对象

if firstUnused != NULL{

如果该对象并不是第一次上锁

那么该对象有三种状态

1.第一次没有锁

2.不是第一次,同一个线程加的锁

3.不是第一次,不同进程加的锁

存到tls临时变量里方便缓存cache查找,如果有多个线程锁同一个对象,必定在cache留下痕迹

}

if (!fastcacheOccupied){

tls_set_direct{DATA_KEY,COUNT_KEY}

}

if (!cache){

fetch_cache(YES)

cache->list[cache->used].data=result

cache->list[cache->used].lockCount = 1

cache->used

if(cache){

for i=0;i<cache->used;i {

SyncCacheItem *item = &cache->list[i]

if (item->data->object!=objcet)继续查找{

result=item->data 寻找下一个节点数据

直到在cache找到,证明不是第一次加锁 如果cache判断为真

找到有两种操作 Required / Releas

break

}

}

}

}

}

}

}

}id2Data结束

总结:Synchronized为何性能如此低,且泛用性高,不用忘记解锁

0 人点赞