美文网首页
iOS 底层 - 多线程之atomic

iOS 底层 - 多线程之atomic

作者: 水中的蓝天 | 来源:发表于2020-04-13 11:43 被阅读0次

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢 !

atom: 原子,不可再分割的单位
atomic: 原子操作
nonatomic: 非原子操作

关于atomic

  • 给属性加上atomic修饰,可以保证属性的setter和getter都是原子性操作,即可以保证setter和getter内部是线程同步(加锁、解锁 -- PropertyLock)的。

  • 它并不能保证使用属性的过程是线程安全的。比如多条线程同时访问这个属性就不能保证线程安全

  • ios 开发中不推荐使用,因为频繁的加锁解锁太消耗性能;mac开发中使用较多。

  • 注意: 是内部线程同步,不能够保证外部的线程同步,就是说无法保证外部访问的线程同步;

为什么使用nonatomic

  • 使用起来对性能的消耗很低
  • 在开发中很少会出现多条线程同时访问同一个属性的情况,即使会遇到也可以通过对访问过程加锁的方式解决,没必要对属性内部加锁。

objc-accessors.m源码


//加锁方案 os_unfair_lock
using spinlock_t = mutex_tt<LOCKDEBUG>;

template <bool Debug>
class mutex_tt : nocopy_t {
    os_unfair_lock mLock;
 public:
    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);
    }
};

散列表
StripedMap<spinlock_t> PropertyLocks;

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
    if (offset == 0) {
        object_setClass(self, newValue);
        return;
    }

    id oldValue;
    //slot: 属性内存地址
    id *slot = (id*) ((char*)self + offset);

    if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    } else {
        if (*slot == newValue) return;
        newValue = objc_retain(newValue);
    }

    if (!atomic) {//是nonatomic属性
        oldValue = *slot;
        *slot = newValue;
    } else {//是atomic属性,就对赋值过程进行加锁
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock(); //加锁
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();//解锁
    }

    objc_release(oldValue);
}

//设置属性值
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) 
{
    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
    bool mutableCopy = (shouldCopy == MUTABLE_COPY);
    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}


//获取属性值
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    if (offset == 0) {
        return object_getClass(self);
    }

    // Retain release world
    id *slot = (id*) ((char*)self + offset);
    if (!atomic) return *slot; //是nonatomic属性,直接返回属性地址
        
    // Atomic retain release world  是atomic属性,就对取值过程进行加锁
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock(); //加锁
    id value = objc_retain(*slot);
    slotlock.unlock();//解锁
    
    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
    return objc_autoreleaseReturnValue(value);
}

相关文章

网友评论

      本文标题:iOS 底层 - 多线程之atomic

      本文链接:https://www.haomeiwen.com/subject/tizwmhtx.html