单例的销毁
Posted WeaterMr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例的销毁相关的知识,希望对你有一定的参考价值。
单例的代码实现
static Person *ple ;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
NSLog(@"2:%ld", predicate);
ple = [[Person alloc] init];
});
单例的底层实现原理
void dispatch_once(dispatch_once_t *val, dispatch_block_t block{
dispatch_once_f(val, block, _dispatch_Block_invoke(block));
}
void
dispatch_once_f(dispatch_once_t *val, void *ctxt, dispatch_function_t func)
{
dispatch_once_gate_t l = (dispatch_once_gate_t)val;
#if !DISPATCH_ONCE_INLINE_FASTPATH || DISPATCH_ONCE_USE_QUIESCENT_COUNTER
uintptr_t v = os_atomic_load(&l->dgo_once, acquire);
// 状态为 DLOCK_ONCE_DONE 直接返回
if (likely(v == DLOCK_ONCE_DONE)) {
return;
}
#if DISPATCH_ONCE_USE_QUIESCENT_COUNTER
if (likely(DISPATCH_ONCE_IS_GEN(v))) {
return _dispatch_once_mark_done_if_quiesced(l, v);
}
#endif
#endif
// 第一次进来 获取锁, 原子操作多线程处理
if (_dispatch_once_gate_tryenter(l)) {
//执行调用
return _dispatch_once_callout(l, ctxt, func);
}
// 有锁锁住的话 会 等待开锁
return _dispatch_once_wait(l);
}
分析:
- 1.内部实现的 val (也就是 static dispatch_once_t predicate ) 这个变量用来获取底层原子性的一个关联。关联一个 uintptr_t 类型 v的一个变量,用来查询。
- 2.当前的 onceToken是一个全局的静态变量。根据每个单利不同,每个静态变量也不同,为了保证唯一性。
- 3.已经处理过一次了,就retune返回出去了。
- 4.当第一次代码执行进来的时候:为了保证线程的安全性把自己锁起来,保证当前任务执行的唯一,防止相同的onceToken进行多次执行。锁住之后进行 block 的调用执行。调用完毕后将锁解开,于此同时会将 v 的值 置为 DLOCK_ONCE_DONE(下次就不会在进入到调用block流程)。
所以保证了单利的唯一性。
如何销毁 ?
通过上面的分析我们可以得到代码执行一次的原因是由于predicate导致,所以当我们销毁的时候也是操作predicate
1.将对应的变量做成全局的变量
//放到外面声明
static Person *ple ;
static dispatch_once_t predicate;
2.添加一个类方法:
+ (void)deallocSM {
predicate = 0;
per = nil;
}
单例线程安全吗 ?
_dispatch_once_gate_tryenter(l)
static inline bool
_dispatch_once_gate_tryenter(dispatch_once_gate_t l)
{
return os_atomic_cmpxchg(&l->dgo_once, DLOCK_ONCE_UNLOCKED,
(uintptr_t)_dispatch_lock_value_for_self(), relaxed);
}
这里是原子操作,并且对线程操作进行加锁处理。_dispatch_lock_value_for_self
是当前队列中的线程空间锁,防止多线程操作 。防止相同的onceToken进行多次执行。线程安全。
以上是关于单例的销毁的主要内容,如果未能解决你的问题,请参考以下文章