1、OSSpinLock(自旋锁) High-level lock
OSSpinLock叫做”自旋锁”,等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
目前已经不再安全,可能会出现优先级反转问题
如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁
需要导入头文件#import <libkern/OSAtomic.h>
#import <libkern/OSAtomic.h>
@interface OSSpinLockDemo()
@property (assign, nonatomic) OSSpinLock lock;
@end
@implementation OSSpinLockDemo
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化锁
self.lock = OS_SPINLOCK_INIT;
//加锁
OSSpinLockLock(&_lock);
//尝试加锁,如果不需要等待就加锁返回ture,如果需要等待就不加锁返回false
//bool result = OSSpinLockTry(&_lock);
[self testSpinLock];
//解锁
OSSpinLockUnlock(&_lock);
}
2、os_unfair_lock(互斥锁) Low-level lock
os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持
从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
需要导入头文件#import <os/lock.h>
#import <os/lock.h>
@interface OSUnfairLockDemo()
@property (assign, nonatomic) os_unfair_lock lock;
@end
@implementation OSUnfairLockDemo
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化锁
self.lock = OS_UNFAIR_LOCK_INIT;
//加锁
os_unfair_lock_lock(&_lock);
//尝试加锁,如果不需要等待就加锁返回ture,如果需要等待就不加锁返回false
//bool result = os_unfair_lock_trylock(&_lock);
[self testUnfairLock];
//解锁
os_unfair_lock_unlock(&_lock);
}
ibireme 大神 《不再安全的 OSSpinLock》 这篇文章表示OSSpinLock不再安全,新版 iOS 中,系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spinlock。
3、pthread_mutex -需要销毁
#import <pthread.h>
/*
/*
* Mutex type attributes
*/
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_ERRORCHECK 1
#define PTHREAD_MUTEX_RECURSIVE 2
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
*/
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t mutex;
@end
@implementation MutexDemo
- (void)viewDidLoad {
[super viewDidLoad];
// 静态初始化
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
// 初始化锁
pthread_mutex_init(_mutex, &attr);
//pthread_mutex_init(_mutex, NULL);//传空也是默认PTHREAD_MUTEX_DEFAULT
// 销毁属性
pthread_mutexattr_destroy(&attr);
pthread_mutex_lock(&_mutex);
[self testMutex];
pthread_mutex_unlock(&_mutex);
}
- (void)testMutex
{
NSLog(@"%s", __func__);
}
- (void)dealloc
{
pthread_mutex_destroy(&_mutex);
}
#import <pthread.h>
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t mutex;
@end
@implementation MutexDemo
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
// 递归锁:允许同一个线程对一把锁进行重复加锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
// 初始化锁
pthread_mutex_init(_mutex, &attr);
// 销毁属性
pthread_mutexattr_destroy(&attr);
[self otherTest];
}
- (void)testMutex
{
NSLog(@"%s", __func__);
}
- (void)otherTest
{
pthread_mutex_lock(&_mutex);
NSLog(@"%s", __func__);
static int count = 0;
if (count < 10) {
count++;
[self otherTest];
}
pthread_mutex_unlock(&_mutex);
}
- (void)dealloc
{
pthread_mutex_destroy(&_mutex);
}
#import <pthread.h>
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t mutex;
@property (assign, nonatomic) pthread_cond_t cond;
@property (strong, nonatomic) NSMutableArray *data;
@end
@implementation MutexDemo
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);//条件锁
// 初始化锁
pthread_mutex_init(&_mutex, &attr);
// 销毁属性
pthread_mutexattr_destroy(&attr);
// 初始化条件
pthread_cond_init(&_cond, NULL);
self.data = [NSMutableArray array];
[self otherTest];
}
- (void)otherTest
{
[[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}
// 生产者-消费者模式
// 线程1
// 删除数组中的元素
- (void)__remove
{
pthread_mutex_lock(&_mutex);
NSLog(@"__remove - begin");
if (self.data.count == 0) {
// 等待
pthread_cond_wait(&_cond, &_mutex);
}
[self.data removeLastObject];
NSLog(@"删除了元素");
pthread_mutex_unlock(&_mutex);
}
// 线程2
// 往数组中添加元素
- (void)__add
{
pthread_mutex_lock(&_mutex);
sleep(1);
[self.data addObject:@"Test"];
NSLog(@"添加了元素");
// 信号
pthread_cond_signal(&_cond);
// 广播
// pthread_cond_broadcast(&_cond);
pthread_mutex_unlock(&_mutex);
}
- (void)dealloc
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
}
4、NSLock
NSLock是对mutex普通锁的封装
5、NSRecursiveLock
NSRecursiveLock也是对mutex递归锁的封装,API跟NSLock基本一致
6、NSCondition
NSCondition是对mutex和cond的封装
@interface NSConditionDemo()
@property (strong, nonatomic) NSCondition *condition;
@property (strong, nonatomic) NSMutableArray *data;
@end
@implementation NSConditionDemo
- (void)viewDidLoad {
[super viewDidLoad];
self.condition = [[NSCondition alloc] init];
self.data = [NSMutableArray array];
[self otherTest];
}
- (void)otherTest
{
[[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}
// 线程1
// 删除数组中的元素
- (void)__remove
{
[self.condition lock];
NSLog(@"__remove - begin");
if (self.data.count == 0) {
// 等待
[self.condition wait];
}
[self.data removeLastObject];
NSLog(@"删除了元素");
[self.condition unlock];
}
// 线程2
// 往数组中添加元素
- (void)__add
{
[self.condition lock];
sleep(1);
[self.data addObject:@"Test"];
NSLog(@"添加了元素");
// 信号
[self.condition signal];
sleep(2);
[self.condition unlock];
}
7、NSConditionLock
NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值,默认为0;
@interface NSConditionLockDemo()
@property (strong, nonatomic) NSConditionLock *conditionLock;
@end
@implementation NSConditionLockDemo
- (void)viewDidLoad {
[super viewDidLoad];
self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
[self otherTest];
}
- (void)otherTest
{
[[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start];
}
- (void)__one
{
[self.conditionLock lock];//不管条件值,直接加锁
NSLog(@"__one");
sleep(1);
[self.conditionLock unlockWithCondition:2];
}
- (void)__two
{
[self.conditionLock lockWhenCondition:2];//必须满足条件才能加锁
NSLog(@"__two");
sleep(1);
[self.conditionLock unlockWithCondition:3];
}
- (void)__three
{
[self.conditionLock lockWhenCondition:3];
NSLog(@"__three");
[self.conditionLock unlock];
}
8、dispatch_semaphore
semaphore叫做”信号量”
信号量的初始值,可以用来控制线程并发访问的最大数量
信号量的初始值为1,代表同时只允许1条线程访问资源,保证线程同步
@interface SemaphoreDemo()
@property (strong, nonatomic) dispatch_semaphore_t semaphore;
@end
@implementation SemaphoreDemo
- (void)viewDidLoad {
[super viewDidLoad];
self.semaphore = dispatch_semaphore_create(5);//设置为1则是串行队列,>1为并发
}
- (void)otherTest
{
for (int i = 0; i < 20; i++) {
[[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
}
}
- (void)test
{
// 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
// 如果信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,然后继续往下执行代码
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
sleep(2);
NSLog(@"test - %@", [NSThread currentThread]);
// 让信号量的值+1
dispatch_semaphore_signal(self.semaphore);
}
9、synchronized(递归锁)
@synchronized是对mutex递归锁的封装,在xcode编写的时候不会有提示,性能比较低。
@synchronized(obj)内部会生成obj对应的递归锁,然后进行加锁、解锁操作
/*
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;
*/
//底层实现 objc_sync.mm objc_sync_enter objc_sync_exit syncData 里面是哈希表查找 c++结构
@synchronized([self class]) {
[self otherTest];
}
性能从高到低排序:os_unfair_lock >OSSpinLock>dispatch_semaphore>pthread_mutex>NSLock>NSCondition>pthread_mutex(recursive)>NSConditionLock>@synchronized(在加锁和解锁的代码上算出所用的时间差)OSSpinLock,dispatch_semaphore的性能远远优于其他的锁,但是OSSpinLock由于优先级反转的问题,苹果在iOS10的时候推出了os_unfair_lock来替代,而且性能不减当年,但是要在iOS10之后才能用(虽然自旋锁的性能优于互斥锁),可以看出@synchronize和NSConditionLock明显性能最差,如果项目中对性能特别敏感,建议使用dispatch_semaphore,如果基于方便的话就用@synchronize也可以,影响不大。