锁
常见锁的类型:
- OSSpinLock
- dispatch_semaphore_t
- os_unfair_lock
- pthread_mutex_t
- NSlock
- NSCondition
- pthread_mutex_t(recursive)
- NSRecursiveLock
- NSConditionLock
- @synchronized
在很多的场景中我们都用到 @synchronized这个锁,我们来分析一下@synchronized的源码
举个?
我们一共有20张票,

然后有好几个窗口在同时卖票,


好了,现在开始卖票

但是我们发现,在票为17张的时候下面显示出18张,这样这个票数便不准确了。
这是因为在同一时刻有多个线程同时操作同一块内存区域,导致数据不准确,我们加一个锁,在同一时刻只有一个线程操作这个票数。


@synchronized
在上面的例子中我们用到了@synchronized锁,它起到一个加锁的效果。有时候我们还会看到下面这种结构。@synchronized是可以实现递归可重入的。那么@synchronized的结构是怎么样子的,是怎么实现加锁的效果的❓。我们来分析源码
@synchronized (p) {
              @synchronized (p1) {
                   
              }
}
复制代码加个断点,看到汇编走到了


找到objc的源码,搜索objc_sync_enter
int objc_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;
}
复制代码从else看出,如果obj为空,则does nothing
看下objc_sync_exit
int objc_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
}
return result;
}
复制代码两者代码很相似,在obj不为空的情况下,分别进行了data->mutex.lock();和bool okay = data->mutex.tryUnlock();操作。
我们看下SyncData* data = id2data(obj, ACQUIRE);主要流程代码
static SyncData* id2data(id object, enum usage why)
{
spinlock_t *lockp = &LOCK_FOR_OBJ(object);
SyncData **listp = &LIST_FOR_OBJ(object);
SyncData* result = NULL;
#if SUPPORT_DIRECT_THREAD_KEYS
bool fastCacheOccupied = NO;
//#define __PTK_FRAMEWORK_OBJC_KEY1 41
SyncData *data = (SyncData *)tls_get_direct(SYNC_DATA_DIRECT_KEY);
//如果有data则走if里面
if(data){...}
SyncCache *cache = fetch_cache(NO);
//Check per-thread cache of already-owned locks for matching object
if (cache) {...}
lockp->lock();
{...}
//创建一个SyncData添加到list
posix_memalign((void **)&result, alignof(SyncData), sizeof(SyncData));
result->object = (objc_object *)object;
result->threadCount = 1;
new (&result->mutex) recursive_mutex_t(fork_unsafe_lock);
result->nextData = *listp;
*listp = result;
done:
    lockp->unlock();
    if (result) {
    //存入cache 等别的操作
    ...
    }
return result;    
复制代码数据结构
spinlock_t *lockp = &LOCK_FOR_OBJ(object);
SyncData **listp = &LIST_FOR_OBJ(object);
复制代码#define LOCK_FOR_OBJ(obj) sDataLists[obj].lock
#define LIST_FOR_OBJ(obj) sDataLists[obj].data
static StripedMap<SyncList> sDataLists;
复制代码我们看下SyncList, StripedMap
struct SyncList {
SyncData *data;
spinlock_t lock;
constexpr SyncList() : data(nil), lock(fork_unsafe_lock) { }
};
template<typename T>
class StripedMap {
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
enum { StripeCount = 8 };
#else
enum { StripeCount = 64 };
#endif
...
}
typedef struct alignas(CacheLineSize) SyncData {
struct SyncData* nextData; //单链表
DisguisedPtr<objc_object> object;
int32_t threadCount; // number of THREADS using this block
recursive_mutex_t mutex;
} SyncData;
复制代码可以看到sDataLists是一个哈希结构
打印一下,由class StripedMap我们使用的模拟器,所以StripeCount = 64,是下面的结构
(StripedMap<SyncList>::PaddedT [64]) array = {
  [0] = {
    value = {
      data = NULL
      lock = {
        mLock = (_os_unfair_lock_opaque = 0)
      }
    }
  }
  [1] = {
    value = {
      data = NULL
      lock = {
        mLock = (_os_unfair_lock_opaque = 0)
      }
    }
  }
  [2] = {
    value = {
      data = NULL
      lock = {
        mLock = (_os_unfair_lock_opaque = 0)
      }
    }
  }
  [3] = {
    value = {
      data = NULL
      lock = {
        mLock = (_os_unfair_lock_opaque = 0)
      }
    }
  }
  [4] = {
    value = {
      data = NULL
      lock = {
        mLock = (_os_unfair_lock_opaque = 0)
      }
    }
  }
  ...
  [63] = {
    value = {
      data = NULL
      lock = {
        mLock = (_os_unfair_lock_opaque = 0)
      }
    }
  }
}
复制代码第一个@synchronized流程
第一个@synchronized进到SyncData* id2data中,由于data为空,也没有cache,则先创建
posix_memalign((void **)&result, alignof(SyncData), sizeof(SyncData));
result->object = (objc_object *)object;
result->threadCount = 1;
new (&result->mutex) recursive_mutex_t(fork_unsafe_lock);
result->nextData = *listp;
*listp = result;
复制代码初始化的threadCount为1
由上面知syncList为如下结构,是一个哈希表,表中每一格代表同一个对象,后面的链表是一个@synchronized锁一次这个对象就一个syncData。

当再次执行@synchronized (p1),如果p1和之前的对象不相同,则走
{
SyncData* p;
SyncData* firstUnused = NULL;
for (p = *listp; p != NULL; p = p->nextData) {
//如果没有相同的object,则这个函数内什么也不做
if ( p->object == object ) {//如果对象相同,则增加threadCount
result = p; 
// atomic because may collide with concurrent RELEASE
OSAtomicIncrement32Barrier(&result->threadCount);
goto done;
}
if ( (firstUnused == NULL) && (p->threadCount == 0) )
firstUnused = p;
}
// no SyncData currently associated with object
if ( (why == RELEASE) || (why == CHECK) )
goto done;
// an unused one was found, use it
if ( firstUnused != NULL ) {
result = firstUnused;
result->object = (objc_object *)object;
result->threadCount = 1;
goto done;
}
}
复制代码最终还是会走
posix_memalign((void **)&result, alignof(SyncData), sizeof(SyncData));
result->object = (objc_object *)object;
result->threadCount = 1;
new (&result->mutex) recursive_mutex_t(fork_unsafe_lock);
result->nextData = *listp;
*listp = result;
复制代码相同的对象
则走
{
fastCacheOccupied = YES;
if (data->object == object) {
// Found a match in fast cache.
uintptr_t lockCount;
result = data;
lockCount = (uintptr_t)tls_get_direct(SYNC_COUNT_DIRECT_KEY);
if (result->threadCount <= 0 || lockCount <= 0) {
_objc_fatal("id2data fastcache is buggy");
}
switch(why) {
case ACQUIRE: {//走这里,lockCount++;锁的次数加一,可重入,递归
lockCount++;
tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);
break;
}
case RELEASE:
lockCount--;
tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);
if (lockCount == 0) {
// remove from fast cache
tls_set_direct(SYNC_DATA_DIRECT_KEY, NULL);
// atomic because may collide with concurrent ACQUIRE
OSAtomicDecrement32Barrier(&result->threadCount);//多线程的体现
}
break;
case CHECK:
// do nothing
break;
}
return result;
}
}
复制代码TLS 线程局部存储(Thread Local Storage,TLS)是操作系统为线程单独提供的私有空间,通常只有有限的容量
objc_sync_exit的时候则会走如下,lockCount==0的时候,则走OSAtomicDecrement32Barrier(&result->threadCount);线程个数减1
lockCount--;
tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);
if (lockCount == 0) {
tls_set_direct(SYNC_DATA_DIRECT_KEY, NULL);
OSAtomicDecrement32Barrier(&result->threadCount);
}
复制代码




















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)
