锁用于解决线程争夺资源的问题,一般分为两种,自旋锁(spin)和互斥锁(mutex)。
互斥锁可以解释为线程获取锁,发现锁被占用,就向系统申请锁空闲时唤醒他并立刻休眠。
自旋锁比较简单,当线程发现锁被占用时,会不断循环判断锁的状态,直到获取。
原子操作的颗粒度最小,只限于读写,对于性能的要求很高,如果使用了互斥锁势必在切换线程上耗费大量资源。相比之下,由于读写操作耗时比较小,能够在一个时间片内完成,自旋更适合这个场景。
但是iOS 10之后,苹果因为一个巨大的缺陷弃用了 OSSpinLock
改为新的 os_unfair_lock
。
新版 iOS 中,系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spin lock。
描述引用自 ibireme 大神的文章。
我的理解是,当低优先级线程获取了锁,高优先级线程访问时陷入忙等状态,由于是循环调用,所以占用了系统调度资源,导致低优先级线程迟迟不能处理资源并释放锁,导致陷入死锁。
那为什么原子操作用的还是 spinlock_t
呢?
using spinlock_t = mutex_tt<LOCKDEBUG>;
using mutex_t = mutex_tt<LOCKDEBUG>;
class mutex_tt : nocopy_t {
os_unfair_lock mLock; //处理了优先级的互斥锁
void lock() {
lockdebug_mutex_lock(this);
os_unfair_lock_lock_with_options_inline
(&mLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
}
void unlock() {
lockdebug_mutex_unlock(this);
os_unfair_lock_unlock_inline(&mLock);
}
}
差点被苹果骗了!原来系统中自旋锁已经全部改为互斥锁实现了,只是名称一直没有更改。
https://www.cnblogs.com/vanch/p/10192002.html
atomic作用:多线程下将属性设置为atomic可以保证读取数据的一致性。因为他将保证数据只能被一个线程占用,也就是说一个线程对属性进行写操作时,会使用自旋锁锁住该属性。不允许其他的线程对其进行读取操作了。
但是它有一个很大的缺点:因为它要使用自旋锁锁住该属性,因此它会消耗更多的资源,性能会很低。要比nonatomic慢20倍。
内部实现:property 的 atomic 是采用 spinlock_t (自旋锁)实现的。
// getter方法
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic)
{
// ...
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// ...
}
//setter方法
// setter
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
// ...
if (!atomic)
{
oldValue = *slot;
*slot = newValue;
}
else
{
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
// ...
}
简而言之,atomic的作用只是给getter和setter加了个锁,atomic只能保证代码进入getter或者setter函数内部时是安全的,一旦出了getter和setter,多线程安全只能靠程序员自己保障了。所以atomic属性和使用property的多线程安全并没什么直接的联系。另外,atomic由于加锁也会带来一些性能损耗,所以我们在编写iOS代码的时候,一般声明property为nonatomic,在需要做多线程安全的场景,自己去额外加锁做同步。
原文:https://www.cnblogs.com/feng9exe/p/14541048.html