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也可以,影響不大。