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为何性能如此低,且泛用性高,不用忘记解锁