加锁 & 死锁

iOS加锁类型

  1. 自旋锁

自旋锁不会让等待的线程休眠. 会一直等待, 效率较高, 互斥锁会让等待的线程休眠

使用自旋锁进行加锁操作 需要导入#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 解锁成功

    */
}
  1. 使用信号量进行加锁
// 使用信号量进行加锁操作
- (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] -->程序结束
     */
}
  1. 使用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
     */
}
  1. 递归锁, 允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作。
- (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);
}
  1. 使用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

 */
}
  1. 使用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);
    });
}
  1. 使用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
     */
}
  1. 使用synchronize进行加锁, @synchronized block 在被保护的代码上暗中添加了一个异常处理。为的是同步某对象时如若抛出异常,锁会被释放掉。@synchronized block 会变成 objc_sync_enterobjc_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
     */
}

  1. 使用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又在等函数执行完毕. 相互僵持的状态, 书都无法继续下去, 造成死锁的状态. 解决: 超时放弃机制, 以确定的顺序执行任务.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值