/* Fast cache: two fixed pthread keys store a single SyncCacheItem. This avoids malloc of the SyncCache for threads that only synchronize a single object at a time. SYNC_DATA_DIRECT_KEY == SyncCacheItem.data SYNC_COUNT_DIRECT_KEY == SyncCacheItem.lockCount */
structSyncList { SyncData *data; spinlock_t lock;
SyncList() : data(nil) { } };
// Use multiple parallel lists to decrease contention among unrelated objects. #define LOCK_FOR_OBJ(obj) sDataLists[obj].lock #define LIST_FOR_OBJ(obj) sDataLists[obj].data static StripedMap<SyncList> sDataLists;
// Begin synchronizing on 'obj'. // Allocates recursive mutex associated with 'obj' if needed. // Returns OBJC_SYNC_SUCCESS once lock is acquired. intobjc_sync_enter(id obj) { int result = OBJC_SYNC_SUCCESS;
if (obj) { SyncData* data = id2data(obj, ACQUIRE); assert(data); data->mutex.lock(); } 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(); }
return result; }
// End synchronizing on 'obj'. // Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR intobjc_sync_exit(id obj) { int result = OBJC_SYNC_SUCCESS; if (obj) { SyncData* data = id2data(obj, RELEASE); if (!data) { result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR; } else { bool okay = data->mutex.tryUnlock(); if (!okay) { result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR; } } } else { // @synchronized(nil) does nothing }
//对于同一个线程来说,有两种缓存方式: //第一种:快速缓存(fastCache),适用于一个线程一次只对一个对象加锁的情况,用宏SUPPORT_DIRECT_THREAD_KEYS来标识 //这种情况意味着同一时间内,线程缓存中只有一个SyncCacheItem对象,键值SYNC_DATA_DIRECT_KEY和SYNC_COUNT_DIRECT_KEY分别对应SyncCacheItem结构体中的SyncData对象和lockCount. #if SUPPORT_DIRECT_THREAD_KEYS // Check per-thread single-entry fast cache for matching object //用于标识当前线程的是否已使用fastCache bool fastCacheOccupied = NO; //直接调用tls_get_direct函数获取SyncData对象 SyncData *data = (SyncData *)tls_get_direct(SYNC_DATA_DIRECT_KEY); if (data) { //标识fastCache已被使用 fastCacheOccupied = YES; //比较fastCache中的SyncData对象中的object与当前同步对象object是否为同一个对象 if (data->object == object) { // Found a match in fast cache. //fastCache中的对象恰好是当前同步对象object,则后续处理直接使用fastCache中SyncData对象 uintptr_t lockCount;
result = data; //获取当前线程对应当前SyncData对象已经加锁的次数 lockCount = (uintptr_t)tls_get_direct(SYNC_COUNT_DIRECT_KEY); //无效的SyncData对象 if (result->threadCount <= 0 || lockCount <= 0) { _objc_fatal("id2data fastcache is buggy"); } //判断当前操作的加锁还是解锁 switch(why) { //加锁 case ACQUIRE: { //加锁一次 lockCount++; //更新已加锁次数 tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount); break; } //解锁 case RELEASE: //解锁一次 lockCount--; //更新已加锁次数 tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount); //已加锁次数为0,表示当前线程对当前同步对象object达到锁平衡,因此不需要再持有当前同步对象。 if (lockCount == 0) { // remove from fast cache //将对应的SyncData对象从线程缓存中移除 tls_set_direct(SYNC_DATA_DIRECT_KEY, NULL); // atomic because may collide with concurrent ACQUIRE //此函数为原子操作函数,用于对32位的threadCount整形变量执行减一操作,且确保线程安全。因为可能存在同一时间多个线程对一个threadCount进行加减操作,避免出现多线程竞争。不同于lockCount,threadCount是多个线程共享的一个变量,用于记录对一个对象加锁的线程个数,threadCount对应的SyncData对象除了线程缓存中持有之外,还存在于全局哈希表sDataLists中,sDataLists哈希表是多个线程共享的数据结构,因此存在多线程访问的可能。而lockCount则与线程一一对应且存储在线程的缓存区中,不存在多线性读写问题,因此不需要加锁。 OSAtomicDecrement32Barrier(&result->threadCount); } break; case CHECK: // do nothing break; }
return result; } } #endif
// Check per-thread cache of already-owned locks for matching object //这是第二章缓存方式:使用SyncCache结构体来维护一个SyncCacheItem数组,这样一个线程就可以处理对多个同步对象。值得注意的是SyncCache与线程也是一对一的关系。 //获取当前线程缓存区中的SyncCache对象 SyncCache *cache = fetch_cache(NO); if (cache) { unsignedint i; //遍历SyncCache对象中的SyncCacheItem数组,匹配当前同步对象object for (i = 0; i < cache->used; i++) { SyncCacheItem *item = &cache->list[i]; if (item->data->object != object) continue;
// Found a match. //当前同步对象object已存在的SyncCache中 //获取对应的SyncData对象 result = item->data; //无效的SyncData对象 if (result->threadCount <= 0 || item->lockCount <= 0) { _objc_fatal("id2data cache is buggy"); } //后续操作同fastCache一样,参考fastCache的注释 switch(why) { case ACQUIRE: item->lockCount++; break; case RELEASE: item->lockCount--; if (item->lockCount == 0) { // remove from per-thread cache cache->list[i] = cache->list[--cache->used]; // atomic because may collide with concurrent ACQUIRE OSAtomicDecrement32Barrier(&result->threadCount); } break; case CHECK: // do nothing break; } return result; } }
// Thread cache didn't find anything. // Walk in-use list looking for matching object // Spinlock prevents multiple threads from creating multiple // locks for the same new object. // We could keep the nodes in some hash table if we find that there are // more than 20 or so distinct locks active, but we don't do that now. //如果当前线程中的缓存中没有找到当前同步对象对应的SyncData对象,则在全局哈希表中查找 //因为全局哈希表是多个线程共享的数据结构,因此需要进行加锁处理 lockp->lock();
{ SyncData* p; SyncData* firstUnused = NULL; //遍历当前同步对象obejct在全局哈希表中的SyncData链表。这里之所以使用链表,是因为哈希表的hash算法不能确保hash的唯一性,存在多个对象对应一个hash值的情况。 for (p = *listp; p != NULL; p = p->nextData) { //哈希表中存在对应的SyncData对象 if ( p->object == object ) { result = p; // atomic because may collide with concurrent RELEASE //此函数为原子操作函数,确保线程安全,用于对32位的threadCount整形变量执行加一操作,表示占用当前同步对象的线程数加1。 OSAtomicIncrement32Barrier(&result->threadCount); goto done; } //用于标记一个空闲的SyncData对象 if ( (firstUnused == NULL) && (p->threadCount == 0) ) firstUnused = p; } // no SyncData currently associated with object //由于此时同步对象object没有对应的SyncData对象,因此RELEASE与CHECK都属于无效操作 if ( (why == RELEASE) || (why == CHECK) ) goto done; // an unused one was found, use it //如果没有找到匹配的SyncData对象且存在空闲的SyncData对象,则直接使用,不需要创建新的SyncData,以提高效率。 if ( firstUnused != NULL ) { result = firstUnused; //关联当前同步对象 result->object = (objc_object *)object; //重置占用线程为1 result->threadCount = 1; goto done; } }
// malloc a new SyncData and add to list. // XXX calling malloc with a global lock held is bad practice, // might be worth releasing the lock, mallocing, and searching again. // But since we never free these guys we won't be stuck in malloc very often. //到这一步说明需要新建一个SyncData对象 result = (SyncData*)calloc(sizeof(SyncData), 1); result->object = (objc_object *)object; result->threadCount = 1; //创建递归互斥锁 new (&result->mutex) recursive_mutex_t(); //以“入栈”的方式加入当前同步对象object对应的SyncData链表 result->nextData = *listp; *listp = result; done: //对全局哈希表的操作结束,解锁 lockp->unlock(); if (result) { // Only new ACQUIRE should get here. // All RELEASE and CHECK and recursive ACQUIRE are // handled by the per-thread caches above. //只有ACQUIRE才需要新建SyncData对象 if (why == RELEASE) { // Probably some thread is incorrectly exiting // while the object is held by another thread. return nil; } if (why != ACQUIRE) _objc_fatal("id2data is buggy"); if (result->object != object) _objc_fatal("id2data is buggy");
//fastCache缓存模式 #if SUPPORT_DIRECT_THREAD_KEYS if (!fastCacheOccupied) { // Save in fast thread cache //直接缓存新建的SyncData对象 tls_set_direct(SYNC_DATA_DIRECT_KEY, result); //设置加锁次数为1 tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)1); } else #endif //SyncCache缓存模式,则直接加入SyncCacheItem数组中 { // Save in thread cache if (!cache) cache = fetch_cache(YES); cache->list[cache->used].data = result; cache->list[cache->used].lockCount = 1; cache->used++; } }