synchronized 详解

关于synchronized

问题:
1、锁是如何和与你传入的@synchronized的对象关联上的?
2、@synchronized 会保持(retain, 增加引用计数)被锁住的对象吗?
3、假如你传入@synchronized的对象在@synchronized的block里面被释放或者被赋值为nil 将会怎么样?

#伪代码:
@synchronized(obj) {
    // do work
}

@try {
    objc_sync_enter(obj);
    // do work
} @finally {
    objc_sync_exit(obj);
}

#使用到的数据结构
typedef struct SyncData {
    id object;
    recursive_mutex_t mutex;
    struct SyncData* nextData;
    int threadCount;
} SyncData;

typedef struct SyncList {
    SyncData *data;
    spinlock_t lock;
} SyncList;

// Use multiple parallel lists to decrease contention among unrelated objects.
#define COUNT 16
#define HASH(obj) ((((uintptr_t)(obj)) >> 5) & (COUNT - 1))
#define LOCK_FOR_OBJ(obj) sDataLists[HASH(obj)].lock
#define LIST_FOR_OBJ(obj) sDataLists[HASH(obj)].data
static SyncList sDataLists[COUNT];

当你调用 objc_sync_enter(obj) 时,它用 obj 内存地址的哈希值查找合适的 SyncData,然后将其上锁。当你调用 objc_sync_exit(obj) 时,它查找合适的 SyncData 并将其解锁。

objc_sync_enter 源码
int objc_sync_enter(id obj)
{
    int result = OBJC_SYNC_SUCCESS;

    if (obj) {
        SyncData* data = id2data(obj, ACQUIRE);
        require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
    
        result = recursive_mutex_lock(&data->mutex);
        require_noerr_string(result, done, "mutex_lock failed");
    } else {
        // @synchronized(nil) does nothing
        if (DebugNilSync) {
            _objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
        }
        objc_sync_nil();
    }

done: 
    return result;
}

回答:
1、你调用synchronized 的每个对象,OC runtime都会为其分配一个递归锁并存在哈希表中。
2、如果在synchronized 内部对象被释放或被设为nil,看起来都OK。
3、注意不要向你的 synchronized block 传nil,这将会从代码中移走线程安全

synchronized 详解

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容