synchronized实现原理及缺陷分析

本文详细分析了synchronized关键字的使用方式、实现机制,包括其依赖的数据结构如OSLockObject、OSSpinLock等。还探讨了使用synchronized时的注意事项和潜在缺陷,例如不能使用非OC对象作为加锁条件,加锁条件为nil的影响,以及在临界区更改加锁条件的风险。通过对这些内容的理解,有助于更好地理解和应用synchronized。
摘要由CSDN通过智能技术生成

@synchronizedObjective-C中提供的一个用来快速加锁操作的关键字,该篇文章就深度分析一下该关键字的实现原理,并从中找出一些使用中的注意实现以及使用缺陷。

一、使用方式

@synchronized关键字的使用十分简单,如下:

- (void)testSynchronized {
    @synchronized (self) {
        NSLog(@"call test synchronized");
    }
}

仅需一个关键字包围并提供一个用来加锁的变量,就能完成对临界区代码的加锁操作,简直无法更加便利快捷。

那么 @synchronized是如何实现加锁操作的呢?我们来进行进一步的分析。

二、实现方式

我们可以通过 clang来将上述代码转换为具体实现源码:

static void _I_CustomObject_testSynchronized(CustomObject * self, SEL _cmd) {
    {
        id _rethrow = 0;
        id _sync_obj = (id)self;
        objc_sync_enter(_sync_obj);
        try {
            struct _SYNC_EXIT { _SYNC_EXIT(id arg) : sync_exit(arg) {}
                ~_SYNC_EXIT() {objc_sync_exit(sync_exit);}
                id sync_exit;
            } _sync_exit(_sync_obj);
            
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p3_pyrv2p4j0gn_yqv6994w1ryr0000gn_T_CustomObject_77509d_mi_0);
        } catch (id e) {
            _rethrow = e;
            
        }
        
        { struct _FIN { _FIN(id reth) : rethrow(reth) {}
            ~_FIN() { if (rethrow) objc_exception_throw(rethrow); }
            id rethrow;
        } _fin_force_rethow(_rethrow);}
    }
}

从上述转换出的源码来看,该关键字将提供的用来加锁的变量赋值给 _sync_obj变量,同时调用 objc_sync_enter方法,在此之后执行临界区代码,执行临界区代码后,由一个 _SYNC_EXIT结构体类型的保存有 _sync_obj变量的结构体变量的销毁方法调用 objc_sync_exit方法;在此之后,若有异常抛出,由一个 _FIN结构体类型的变量来处理抛出的异常。

由上述流程不难看出,临界区代码是在一对 objc_sync_enter方法和 objc_sync_exit方法之间执行的,所以 objc_sync_enter方法完成的是加锁操作, objc_sync_exit方法完成的是解锁操作。

这两个方法是如何运行的呢?在开始探索这两个方法实现原理之前,先介绍一下相关的数据结构以及知识。

三、相关数据结构及知识

1. SyncData

typedef struct SyncData {
    struct SyncData* nextData;          //指向下一个SyncData
    DisguisedPtr<objc_object> object;   //当前加锁的对象
    int32_t threadCount;                //使用该对象进行加锁的线程数
    recursive_mutex_t mutex;            //用于加锁的递归锁
} SyncData;

该数据结构为 @synchronized实现原理中最基本的数据结构,其中记录了提供的用于加锁的变量,使用该变量加锁的线程数以及与该变量一一对应的一个锁。

2. SyncCacheItem

typedef struct {
    SyncData *data;             //该缓存条目对应的SyncData
    unsigned int lockCount;     //该对象在该线程中被加锁的次数
} SyncCacheItem;

该数据结构用来记录某个 SyncData在某个线程中被加锁的记录,由定义可知,一个 SyncData可以被多个 SyncCacheItem持有。

3. SyncCache

typedef struct SyncCache {
    unsigned int allocated;     //该缓存此时对应的缓存大小
    unsigned int used;          //该缓存此时对应的已使用缓存大小
    SyncCacheItem list[0];    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值