美文网首页
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