OSSpinLock 自旋锁 ( heigh-leve Lock、自旋锁)
使用需导入头文件
#import <libkern/OSAtomic.h>
使用方式
OSSpinLock _lock = OS_SPINLOCK_INIT; // 初始化一个锁
OSSpinLockLock(&_lock); // 上锁
OSSpinLockUnlock(&_lock); // 解锁
OSSpinLockTry(&_lock); // 尝试加锁 如果不能加锁 返回No
存在问题
1.线程优先级反转
2.iOS10之后过期
自旋锁,线程不会休眠,所以当低优先级线程先对操作进行Lock操作后,CPU调度高优先级线程操作,由于低优先级别UnLock,此时调用高优先级线程。高优先级无法处理该操作,而高优先级线程一直调用CPU资源, 系统等待高优先级线程执行完毕后才给低优先级线程资源。
os_unfair_lock (low-level Lock、互斥锁 )
使用需导入头文件
import <os.lock.h>
使用方式
os_unfair_lock _lock = OS_UNFAIR_LOCK_INIT; // 初始化锁
os_unfair_lock_lock(&_lock); // 上锁
os_unfair_lock_unlock(&_lock); // 解锁
os_unfair_lock_trylock(&_lock); // 尝试加锁 如果不能加锁 返回No复
ptheard_mutex
使用需导入头文件
#import "pthread.h"
使用方式
1.属性初始化
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
// 设置锁的描述
// PTHREAD_MUTEX_DEFAULT为一般互斥锁
// PTHREAD_MUTEX_RECURSIVE为递归锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); // 普通互斥锁
// 初始化锁
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, &attr);
// 销毁属性
pthread_mutexattr_destroy(&attr);
// 加锁
pthread_mutex_lock(&mutex);
// 解锁
pthread_mutex_unlock(&mutex);
2.静态初始化
// 静态初始化
// 属性为 PTHREAD_MUTEX_DEFAULT
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3.无属性初始化
// 初始化锁
// 属性为 PTHREAD_MUTEX_DEFAULT
pthread_mutex_t mutex;
pthread_mutex_init(mutex, NULL);
4.递归锁说明
// 允许同一线程重复加锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
5.拓展使用
// 注意 pthread_cond_wait 和 pthread_cond_signal 不可在统一线程被调用
// 原因是 pthread_cond_wait 会使线程休眠
// 初始化条件
pthread_cond_t cond
pthread_cond_init(&cond, NULL);
// 等待信号 同时解锁mutex
pthread_cond_wait(&cond, &mutex);
// 发送信号 继续进行 pthread_cond_wait 后续逻辑
pthread_cond_signal(&cond);
NSLock & NSRecursiveLock & NSCondition & NSConditionLock
可以查看源码 NSLock.swift
也可以查看 GNUstep
通过汇编分析出来的代码实现。链接地址
发现其内部封装的 ptheard_mutex
本初就不做多介绍了。
Dispatch_semaphore
Dispatch_semaphore 可以控制线程的个数 当控制线程个数为1的时候 能确保同时只有1条线程去访问,已达到确保线程安全的目的
使用方式
// 设置最大控制线程数量 number
dispatch_semaphore_t semaphore = dispatch_semaphore_create(number);
// 如果信号量<=0 当前线程就会进入休眠状态 直到信号量的值>0
// 如果信号值>0 就-1 然后执行后续代码
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// do something
// 信号量+1
dispatch_semaphore_signal(semaphore);
dispatch_queue(DISPATCH_QUEUE_SERIAL)
串行队列,当在一个串行队列执行的时候,只有一个线程,能确保线程安全
@synchronized
本质上也是对ptheard_mutex
的封装.可以去runtime源码中objc-sync.mm
文件查看。
Atomic
如果成员变量声明成为atomic
的话。会在set
和get
方法中添加锁。
源码可以查看runtime中的objc-accessors.mm
文件
get 函数
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);
// 如果不加锁 直接返回值
if (!atomic) return *slot;
// 内部封装的 os_unfair_lock 锁
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
set 函数
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}