美文网首页
iOS 锁 多线程

iOS 锁 多线程

作者: 獨荹儛臨 | 来源:发表于2018-03-07 16:45 被阅读18次

锁的作用就是为了线程安全、 在多线程的时候 如果同时调用一个资源、可能会导致数据
错乱, 例子:FMDB 句柄操作 不能同时出现两个操作 否则会出现数据库锁死
@synchronized 互斥锁
NSRecursiveLock 递归锁
NSConditionLock 条件锁
NSLock 对象锁
dispatch_semaphore 信号量实现加锁

1、@synchronized在两个同步线程中 同时操作一个方法 不加锁的话 如下

    _count = 5;
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        [self dosomething];
    });
    dispatch_async(queue, ^{
        [self dosomething];
    });
- (void)dosomething
{
    while (1) {
        //@synchronized(self){
            [NSThread sleepForTimeInterval:1];
            if (_count >0) {
                _count --;
                NSLog(@"_count=%ld, Thread:%@",_count,[NSThread currentThread]);
            }else
            {
                NSLog(@"end Thread:%@",[NSThread currentThread]);
                break;
            }
       // }
    }
}

未加锁
2018-03-07 15:09:01.885914+0800 TableViewDemo[8120:268177] _count=4, Thread:<NSThread: 0x604000071700>{number = 3, name = (null)}
2018-03-07 15:09:01.885914+0800 TableViewDemo[8120:268179] _count=3, Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
2018-03-07 15:09:02.889618+0800 TableViewDemo[8120:268179] _count=1, Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
2018-03-07 15:09:02.889618+0800 TableViewDemo[8120:268177] _count=2, Thread:<NSThread: 0x604000071700>{number = 3, name = (null)}
2018-03-07 15:09:03.893241+0800 TableViewDemo[8120:268179] _count=0, Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}
2018-03-07 15:09:03.893241+0800 TableViewDemo[8120:268177] end Thread:<NSThread: 0x604000071700>{number = 3, name = (null)}
2018-03-07 15:09:04.897898+0800 TableViewDemo[8120:268179] end Thread:<NSThread: 0x60c000078d40>{number = 4, name = (null)}

加入了互斥锁 
2018-03-07 15:10:36.976073+0800 TableViewDemo[8241:269755] _count=4, Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
2018-03-07 15:10:37.979788+0800 TableViewDemo[8241:269754] _count=3, Thread:<NSThread: 0x608000261dc0>{number = 4, name = (null)}
2018-03-07 15:10:38.982916+0800 TableViewDemo[8241:269755] _count=2, Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
2018-03-07 15:10:39.983438+0800 TableViewDemo[8241:269754] _count=1, Thread:<NSThread: 0x608000261dc0>{number = 4, name = (null)}
2018-03-07 15:10:40.988521+0800 TableViewDemo[8241:269755] _count=0, Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}
2018-03-07 15:10:41.992316+0800 TableViewDemo[8241:269754] end Thread:<NSThread: 0x608000261dc0>{number = 4, name = (null)}
2018-03-07 15:10:42.994284+0800 TableViewDemo[8241:269755] end Thread:<NSThread: 0x60800007c140>{number = 3, name = (null)}

以上很明显的看到数据错乱了

2、 NSLock 相同的情况

        [_mutelock lock];
        [NSThread sleepForTimeInterval:1];
        if (_count >0) {
            _count --;
            NSLog(@"_count=%ld, Thread:%@",_count,[NSThread currentThread]);
        }else
        {
            NSLog(@"end Thread:%@",[NSThread currentThread]);
            [_mutelock unlock];
            break;
        }
        [_mutelock unlock];

结果:
2018-03-07 15:19:40.867255+0800 TableViewDemo[8817:280242] _count=4, Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
2018-03-07 15:19:41.869909+0800 TableViewDemo[8817:280238] _count=3, Thread:<NSThread: 0x608000264900>{number = 4, name = (null)}
2018-03-07 15:19:42.871598+0800 TableViewDemo[8817:280242] _count=2, Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
2018-03-07 15:19:43.872715+0800 TableViewDemo[8817:280238] _count=1, Thread:<NSThread: 0x608000264900>{number = 4, name = (null)}
2018-03-07 15:19:44.873510+0800 TableViewDemo[8817:280242] _count=0, Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}
2018-03-07 15:19:45.874513+0800 TableViewDemo[8817:280238] end Thread:<NSThread: 0x608000264900>{number = 4, name = (null)}
2018-03-07 15:19:46.879986+0800 TableViewDemo[8817:280242] end Thread:<NSThread: 0x60400007ebc0>{number = 3, name = (null)}

3、 递归Block 出现Lock 锁死情况 这个时候就需要用到递归锁

    dispatch_async(queue, ^{
        static void (^TestBlcok)(int);
        TestBlcok = ^(int value){
            [_mutelock lock];
            if (value > 0) {
                [NSThread sleepForTimeInterval:1];

                NSLog(@"value=%d, Thread:%@",value,[NSThread currentThread]);
                TestBlcok(value-1);
            }
            [_mutelock unlock];
        };
        TestBlcok(5);
    });


//这段代码是一个典型的死锁情况。在我们的线程中
RecursiveMethod是递归调用的。所以每次进入这个block时,都会去加一次锁
//,而从第二次开始,由于锁已经被使用了且没有解锁,
//所以它需要等待锁被解除,这样就导致了死锁,线程被阻塞住了。调试器中会输出如下信息:

将_mutelock 替换为_recursiveLock = [[NSRecursiveLock alloc] init];解决问题
在这种情况下,我们就可以使用NSRecursiveLock。它可以允许同一线程多次加锁,而不会造成死锁。递归锁会跟踪它被lock的次数。每次成功的lock都必须平衡调用unlock操作。只有所有达到这种平衡,锁最后才能被释放,以供其它线程使用。

4、 NSConditionLock 条件锁

    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (int i = 0; i<=3; i++) {
            [_conditionLock lock];
            [_conditionLock unlockWithCondition:i];
            NSLog(@"Thread1:%@ i = %d",[NSThread currentThread],i);
            sleep(1);
        }
    });
    dispatch_async(queue, ^{
        [_conditionLock lockWhenCondition:2];
        NSLog(@"Thread2:%@",[NSThread currentThread]);
        [_conditionLock unlock];
    });

2018-03-07 15:55:47.975921+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 0
2018-03-07 15:55:48.981407+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 1
2018-03-07 15:55:49.984681+0800 TableViewDemo[10049:317786] Thread2:<NSThread: 0x604000072c00>{number = 4, name = (null)}
2018-03-07 15:55:49.984672+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 2
2018-03-07 15:55:50.989460+0800 TableViewDemo[10049:317781] Thread1:<NSThread: 0x608000276500>{number = 3, name = (null)} i = 3
  • 信号量 dispatch_semaphore_t 可以控制两个线程之间的交互
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    //线程1
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务1");
        sleep(10);
        dispatch_semaphore_signal(semaphore);
    });

    //线程2
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务2");
        dispatch_semaphore_signal(semaphore);
    });

结果就是线程1 Sleep 10s 才执行线程二
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
创建一个信号量、就好比停车位只有一个

相关文章

  • 起底多线程同步锁(iOS)

    起底多线程同步锁(iOS) 起底多线程同步锁(iOS)

  • 多线程 (三)iOS中的锁

    ios 多线程--锁

  • OC--各种线程锁

    参考:正确使用多线程同步锁@synchronized()iOS中的锁iOS多线程安全详解iOS 常见知识点(三):...

  • iOS 多线程

    iOS中的各种锁iOS多线程到底不安全在哪里?

  • GCD练习

    GCD练习 ios 多线程 GCD : ios 多线程 全剧队列,异步执行 线程间通信 信号量 文件锁 单利模式 ...

  • iOS 多线程

    参考链接 iOS多线程iOS 多线程:『GCD』详尽总结iOS简单优雅的实现复杂情况下的串行需求(各种锁、GCD ...

  • iOS中的锁

    起底多线程同步锁(iOS) OSSpinLock NSLock NSRecursiveLock 同步 NSCond...

  • iOS端sqlite3 的线程安全

    sqlite3 多线程和锁 ,优化插入速度及性能优化这篇博客,着重介绍了sqlite3 多线程和锁。这里针对iOS...

  • iOS中的锁

    锁是一种同步机制,用于多线程环境中对资源访问的限制iOS中常见锁的性能对比图(摘自:ibireme): iOS锁的...

  • iOS 多线程,自旋锁和互斥锁详解

    iOS 多线程,自旋锁和互斥锁详解[https://www.jianshu.com/p/a49739c41bac]...

网友评论

      本文标题:iOS 锁 多线程

      本文链接:https://www.haomeiwen.com/subject/esbjfftx.html