iOS加锁类型
- 自旋锁
自旋锁不会让等待的线程休眠. 会一直等待, 效率较高, 互斥锁会让等待的线程休眠
使用自旋锁进行加锁操作 需要导入#import <libkern/OSAtomic.h>
- (void)osspinLock
{
__block OSSpinLock spinlock = OS_SPINLOCK_INIT;
// thread1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 准备上锁");
OSSpinLockLock(&spinlock);
NSLog(@"-->this is thread1");
NSLog(@"-->sleep");
sleep(5);
OSSpinLockUnlock(&spinlock);
NSLog(@"线程1 解锁成功");
});
// thread2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 准备上锁");
OSSpinLockLock(&spinlock);
NSLog(@"-->this is thread2");
OSSpinLockUnlock(&spinlock);
NSLog(@"线程2 解锁成功");
});
/* 两种可能的输出
2021-04-16 10:16:59.864822+0800 note[50234:1108375] 线程2 准备上锁
2021-04-16 10:16:59.864845+0800 note[50234:1108380] 线程1 准备上锁
2021-04-16 10:16:59.864968+0800 note[50234:1108375] -->this is thread2
2021-04-16 10:16:59.865052+0800 note[50234:1108375] 线程2 解锁成功
2021-04-16 10:16:59.866071+0800 note[50234:1108380] -->this is thread1
2021-04-16 10:16:59.866166+0800 note[50234:1108380] -->sleep
2021-04-16 10:17:04.868256+0800 note[50234:1108380] 线程1 解锁成功
2021-04-16 10:16:34.912127+0800 note[50217:1107720] 线程1 准备上锁
2021-04-16 10:16:34.912134+0800 note[50217:1107716] 线程2 准备上锁
2021-04-16 10:16:34.912258+0800 note[50217:1107720] -->this is thread1
2021-04-16 10:16:34.912339+0800 note[50217:1107720] -->sleep
2021-04-16 10:16:39.915603+0800 note[50217:1107720] 线程1 解锁成功
2021-04-16 10:16:39.929116+0800 note[50217:1107716] -->this is thread2
2021-04-16 10:16:39.929542+0800 note[50217:1107716] 线程2 解锁成功
*/
}
- 使用信号量进行加锁
// 使用信号量进行加锁操作
- (void)semaphore
{
dispatch_semaphore_t signal = dispatch_semaphore_create(0); //传入值必须 >=0, 若传入为0则阻塞线程并等待timeout,时间到后会执行其后的语句
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"aikesi:start sleep");
sleep(4);
NSLog(@"-->finish sleep");
dispatch_semaphore_signal(signal);
NSLog(@"-->等待完毕");
});
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER); // 一直等
NSLog(@"-->finish");
NSLog(@"-->程序结束");
/*
2021-04-16 10:33:55.790868+0800 note[50435:1121566] aikesi:start sleep
2021-04-16 10:33:59.792181+0800 note[50435:1121566] -->finish sleep
2021-04-16 10:33:59.792586+0800 note[50435:1121493] -->finish
2021-04-16 10:33:59.792593+0800 note[50435:1121566] -->等待完毕
2021-04-16 10:33:59.792938+0800 note[50435:1121493] -->程序结束
*/
}
- 使用pthread_mutex 进行加锁操作
//#import <pthread/pthread.h>
- (void)mutex
{
// pthread_mutex_t mutex = PTHREAD_ONCE_INIT
static pthread_mutex_t plock;
pthread_mutex_init(&plock, NULL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"thread1 start");
pthread_mutex_lock(&plock);
for (int i = 0; i<3; i++) {
NSLog(@"thread1 execute task");
}
pthread_mutex_unlock(&plock);
NSLog(@"thread1 finish and un lock");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"thread2 start");
pthread_mutex_lock(&plock);
for (int i = 0; i<3; i++) {
NSLog(@"thread2 execute task");
}
pthread_mutex_unlock(&plock);
NSLog(@"thread2 finish and un lock");
});
// pthread_mutex_trylock(&plock); 尝试加锁
/* 线程2先拿到锁, 加锁后开始执行任务, 执行完成后解锁, 解锁后线程1才开始执行, 到最后结束
2021-04-16 11:25:38.436146+0800 note[50981:1150258] thread2 start
2021-04-16 11:25:38.436145+0800 note[50981:1150263] thread1 start
2021-04-16 11:25:38.436290+0800 note[50981:1150258] thread2 execute task
2021-04-16 11:25:38.436380+0800 note[50981:1150258] thread2 execute task
2021-04-16 11:25:38.436469+0800 note[50981:1150258] thread2 execute task
2021-04-16 11:25:38.436592+0800 note[50981:1150258] thread2 finish and un lock
2021-04-16 11:25:38.436706+0800 note[50981:1150263] thread1 execute task
2021-04-16 11:25:38.436927+0800 note[50981:1150263] thread1 execute task
2021-04-16 11:25:38.438426+0800 note[50981:1150263] thread1 execute task
2021-04-16 11:25:38.438554+0800 note[50981:1150263] thread1 finish and un lock
*/
}
- 递归锁, 允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作。
- (void)mutex_recursive
{
static pthread_mutex_t plock;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);// 设置锁类型
pthread_mutex_init(&plock, &attr);
pthread_mutexattr_destroy(&attr);
static void(^TestBlock)(int count);
TestBlock = ^(int count){
pthread_mutex_lock(&plock);
if (count > 0) {
NSLog(@"count:%d",count);
count--;
TestBlock(count);
}else{
NSLog(@"finish");
}
pthread_mutex_unlock(&plock);
};
TestBlock(7);
}
- 使用NSLock 进行加锁
- (void)LOCK
{
NSLock *LOCK = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"entering thread 1");
[LOCK lock];
sleep(3);
[LOCK unlock];
NSLog(@"thread1 finished");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"entering thread 2");
[LOCK lock];
for (int i = 0; i<10; i++) {
NSLog(@"i:%d",i);
}
[LOCK unlock];
NSLog(@"thread2 finished");
});
/* 谁先拿到锁, 就限制性该线程内的代码
2021-04-16 12:38:51.932813+0800 note[51574:1188694] entering thread 1
2021-04-16 12:38:51.932813+0800 note[51574:1188691] entering thread 2
2021-04-16 12:38:54.934238+0800 note[51574:1188694] thread1 finished
2021-04-16 12:38:54.934238+0800 note[51574:1188691] i:0
2021-04-16 12:38:54.934710+0800 note[51574:1188691] i:1
2021-04-16 12:38:54.935044+0800 note[51574:1188691] i:2
2021-04-16 12:38:54.935317+0800 note[51574:1188691] i:3
2021-04-16 12:38:54.935484+0800 note[51574:1188691] i:4
2021-04-16 12:38:54.935614+0800 note[51574:1188691] i:5
2021-04-16 12:38:54.935745+0800 note[51574:1188691] i:6
2021-04-16 12:38:54.935918+0800 note[51574:1188691] i:7
2021-04-16 12:38:54.936366+0800 note[51574:1188691] i:8
2021-04-16 12:38:54.936826+0800 note[51574:1188691] i:9
2021-04-16 12:38:54.937268+0800 note[51574:1188691] thread2 finished
*/
}
- 使用NSRecursiveLock递归锁
// 使用NSRecursiveLock
- (void)recursive
{
NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc]init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void(^testBlock)(int age);
testBlock = ^(int age){
[recursiveLock lock];
if (age > 0) {
NSLog(@"age:%d",age);
age--;
testBlock(age);
}else{
NSLog(@"finished");
}
[recursiveLock unlock];
};
testBlock(10);
});
}
- 使用condition进行加锁
- (void)condition
{
NSCondition *condition = [[NSCondition alloc]init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"entering thread 1");
[condition lock];
NSLog(@"sleeping");
sleep(5);
[condition unlock];
NSLog(@"thread1 finished");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"entering thread 2");
[condition lock];
for (int i = 0; i<10; i++) {
NSLog(@"i:%d",i);
}
[condition unlock];
NSLog(@"thread2 finished");
});
/* 当线程2先拿到锁的时候, 先执行完毕线程2的代码, 再去执行线程1的代码
2021-04-16 12:49:52.749477+0800 note[51690:1195973] entering thread 2
2021-04-16 12:49:52.749477+0800 note[51690:1195977] entering thread 1
2021-04-16 12:49:52.749592+0800 note[51690:1195973] i:0
2021-04-16 12:49:52.749671+0800 note[51690:1195973] i:1
2021-04-16 12:49:52.749749+0800 note[51690:1195973] i:2
2021-04-16 12:49:52.749844+0800 note[51690:1195973] i:3
2021-04-16 12:49:52.749930+0800 note[51690:1195973] i:4
2021-04-16 12:49:52.750158+0800 note[51690:1195973] i:5
2021-04-16 12:49:52.751656+0800 note[51690:1195973] i:6
2021-04-16 12:49:52.753488+0800 note[51690:1195973] i:7
2021-04-16 12:49:52.753565+0800 note[51690:1195973] i:8
2021-04-16 12:49:52.753632+0800 note[51690:1195973] i:9
2021-04-16 12:49:52.753717+0800 note[51690:1195973] thread2 finished
2021-04-16 12:49:52.753729+0800 note[51690:1195977] sleeping
2021-04-16 12:49:57.757300+0800 note[51690:1195977] thread1 finished
*/
/* 当线程1先拿到锁的时候, 限制性完毕线程1的代码 执行完毕之后再去执行线程2的代码
2021-04-16 12:51:22.292263+0800 note[51718:1198341] entering thread 1
2021-04-16 12:51:22.292280+0800 note[51718:1198338] entering thread 2
2021-04-16 12:51:22.292381+0800 note[51718:1198341] sleeping
2021-04-16 12:51:27.293067+0800 note[51718:1198341] thread1 finished
2021-04-16 12:51:27.293083+0800 note[51718:1198338] i:0
2021-04-16 12:51:27.293485+0800 note[51718:1198338] i:1
2021-04-16 12:51:27.293799+0800 note[51718:1198338] i:2
2021-04-16 12:51:27.294082+0800 note[51718:1198338] i:3
2021-04-16 12:51:27.294259+0800 note[51718:1198338] i:4
2021-04-16 12:51:27.294388+0800 note[51718:1198338] i:5
2021-04-16 12:51:27.294582+0800 note[51718:1198338] i:6
2021-04-16 12:51:27.295269+0800 note[51718:1198338] i:7
2021-04-16 12:51:27.295768+0800 note[51718:1198338] i:8
2021-04-16 12:51:27.296238+0800 note[51718:1198338] i:9
2021-04-16 12:51:27.296667+0800 note[51718:1198338] thread2 finished
*/
}
- 使用synchronize进行加锁,
@synchronized block
在被保护的代码上暗中添加了一个异常处理。为的是同步某对象时如若抛出异常,锁会被释放掉。@synchronized block
会变成objc_sync_enter
和objc_sync_exit
的成对儿调用。
- (void)synhcronize
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Entering thread1");
@synchronized (self) {
for (int i = 0; i<3;i++) {
NSLog(@"i:%d",i);
}
NSLog(@"thread1 finished");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Entering thread2");
@synchronized (self) {
sleep(3);
for (int i = 0; i<3;i++) {
NSLog(@"I:%d",i);
}
NSLog(@"thread2 finished");
}
});
/* thread 1先拿到锁, 执行完后再去执行thread2
2021-04-16 15:52:29.449776+0800 note[52526:1256958] Entering thread2
2021-04-16 15:52:29.449776+0800 note[52526:1256960] Entering thread1
2021-04-16 15:52:29.449907+0800 note[52526:1256960] i:0
2021-04-16 15:52:29.449988+0800 note[52526:1256960] i:1
2021-04-16 15:52:29.450076+0800 note[52526:1256960] i:2
2021-04-16 15:52:29.450166+0800 note[52526:1256960] thread1 finished
2021-04-16 15:52:32.450618+0800 note[52526:1256958] I:0
2021-04-16 15:52:32.451014+0800 note[52526:1256958] I:1
2021-04-16 15:52:32.451470+0800 note[52526:1256958] I:2
2021-04-16 15:52:32.451687+0800 note[52526:1256958] thread2 finished
*/
/* thread2 先拿到锁, 执行完毕后再去执行thread1
2021-04-16 15:54:24.875181+0800 note[52576:1259843] Entering thread2
2021-04-16 15:54:24.875181+0800 note[52576:1259849] Entering thread1
2021-04-16 15:54:27.876571+0800 note[52576:1259843] I:0
2021-04-16 15:54:27.877020+0800 note[52576:1259843] I:1
2021-04-16 15:54:27.877570+0800 note[52576:1259843] I:2
2021-04-16 15:54:27.877809+0800 note[52576:1259843] thread2 finished
2021-04-16 15:54:27.877984+0800 note[52576:1259849] i:0
2021-04-16 15:54:27.878111+0800 note[52576:1259849] i:1
2021-04-16 15:54:27.878243+0800 note[52576:1259849] i:2
2021-04-16 15:54:27.878363+0800 note[52576:1259849] thread1 finished
*/
}
- 使用NSCondition实现条件锁
- (void)conditionLock
{
//NSConditionLock可以实现任务之间的依赖关系。
NSConditionLock *conditionLock = [[NSConditionLock alloc]initWithCondition:99];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Entering thread1");
[conditionLock lockWhenCondition:99];
NSLog(@"thread1 sleeping");
sleep(2);
for (int i = 0; i<3;i++) {
NSLog(@"i-1:%d",i);
}
NSLog(@"thread1 finished");
[conditionLock unlockWithCondition:100];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Entering thread2");
[conditionLock lockWhenCondition:101];
NSLog(@"thread2 sleeping");
sleep(2);
for (int i = 0; i<3;i++) {
NSLog(@"i-2:%d",i);
}
NSLog(@"thread2 finished");
[conditionLock unlockWithCondition:102];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"Entering thread3");
[conditionLock lockWhenCondition:100];
NSLog(@"thread3 sleeping");
sleep(2);
for (int i = 0; i<3;i++) {
NSLog(@"i-3:%d",i);
}
NSLog(@"thread3 finished");
[conditionLock unlockWithCondition:101];
});
/* 线程1拿到锁后, 条件与初始创建的条件一直, 开始加锁, 执行完毕后解锁, 并将条件修改为100
线程3符合条件, 开始加锁, 执行完毕后解锁, 并将条件修改为101
线程2符合101条件, 开始解锁执行代码, 执行完毕后解锁. 程序执行完毕
2021-04-16 16:25:26.747210+0800 note[52773:1276164] Entering thread1
2021-04-16 16:25:26.747210+0800 note[52773:1276167] Entering thread2
2021-04-16 16:25:26.747214+0800 note[52773:1276169] Entering thread3
2021-04-16 16:25:26.747334+0800 note[52773:1276164] thread1 sleeping
2021-04-16 16:25:28.752673+0800 note[52773:1276164] i-1:0
2021-04-16 16:25:28.753028+0800 note[52773:1276164] i-1:1
2021-04-16 16:25:28.753473+0800 note[52773:1276164] i-1:2
2021-04-16 16:25:28.753868+0800 note[52773:1276164] thread1 finished
2021-04-16 16:25:28.754137+0800 note[52773:1276169] thread3 sleeping
2021-04-16 16:25:30.758152+0800 note[52773:1276169] i-3:0
2021-04-16 16:25:30.758561+0800 note[52773:1276169] i-3:1
2021-04-16 16:25:30.758950+0800 note[52773:1276169] i-3:2
2021-04-16 16:25:30.759207+0800 note[52773:1276169] thread3 finished
2021-04-16 16:25:30.759386+0800 note[52773:1276167] thread2 sleeping
2021-04-16 16:25:32.764758+0800 note[52773:1276167] i-2:0
2021-04-16 16:25:32.765104+0800 note[52773:1276167] i-2:1
2021-04-16 16:25:32.765414+0800 note[52773:1276167] i-2:2
2021-04-16 16:25:32.765818+0800 note[52773:1276167] thread2 finished
*/
}
死锁原因
死锁多个线程在运行过程中因争夺资源而造成相互等待的一种僵局.
eg:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"-->:view did load");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"-->:lock the thred");
});
}
在viewDidLoad中给主线程的队列中添加同步任务, 因为任务是同步的所以立刻要执行, 只有执行完成后, viewDidLoad才能继续往下执行. 但是队列的特点是FIFO, 这个同步函数是后添加的, 只有等待viewDidLoad执行完毕后才会继续执行, 这样就会进入函数在等viewDidLoad执行完毕, viewDidLoad又在等函数执行完毕. 相互僵持的状态, 书都无法继续下去, 造成死锁的状态. 解决: 超时放弃机制, 以确定的顺序执行任务.