關于synchronized
問題:
1嗤栓、鎖是如何和與你傳入的@synchronized的對象關聯(lián)上的?
2遮咖、@synchronized 會保持(retain, 增加引用計數(shù))被鎖住的對象嗎熬拒?
3非春、假如你傳入@synchronized的對象在@synchronized的block里面被釋放或者被賦值為nil 將會怎么樣?
#偽代碼:
@synchronized(obj) {
// do work
}
@try {
objc_sync_enter(obj);
// do work
} @finally {
objc_sync_exit(obj);
}
#使用到的數(shù)據(jù)結(jié)構(gòu)
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];
當你調(diào)用 objc_sync_enter(obj) 時雹食,它用 obj 內(nèi)存地址的哈希值查找合適的 SyncData畜普,然后將其上鎖。當你調(diào)用 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、你調(diào)用synchronized 的每個對象街立,OC runtime都會為其分配一個遞歸鎖并存在哈希表中舶衬。
2、如果在synchronized 內(nèi)部對象被釋放或被設為nil赎离,看起來都OK逛犹。
3、注意不要向你的 synchronized block 傳nil梁剔,這將會從代碼中移走線程安全