锁的笔记

线程锁的几种介绍

  1. 互斥锁(又名同步锁)。即只有当锁处于打开状态下才能被使用。NSLock,或者@synchronized,C里用pthread_mutex_t。说的都是一个东西,这个没什么好说的,就是简单,好用,线程安全的好帮手,主要是防止几个线程同时操作一个可变容器。
  2. 递归锁。NSRecursiveLock主要是用在循环递归的时候来加锁的。这个东西是允许重复加锁,只要加锁和解锁的次数一致就会释放这个锁(同一线程内部受这个限制,不同线程才需要他收支平衡才能开锁),否则即死锁。
  3. 条件锁。NSConditionLock当满足条件的时候这个锁才会解开。当我们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁。

下面举例说明下

NSLock *theLock = [[NSLock alloc] init];
    
// 创建递归方法
static void (^testCode)(int);
testCode = ^(int value) {
    [theLock lock];
    if (value > 0)
    {
        NSLog(@"int:%d",value);
        [NSThread sleepForTimeInterval:1];
        testCode(value - 1);
    }
    NSLog(@"next");
    [theLock unlock];
};

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    testCode(5);
});
    

这个栗子有兴趣的朋友可以run下,根本走不到打印next的那,为什么呢??

原因很简单,因为当进入到递归里的时候,刚进入testCode(value - 1);的时候就走不动了,因为这个锁被互斥了,被锁住了。所以下面的代码都不能往下走了。这就是互斥的好处,安全。但不好的是,这里并没有达到我们的预期,没有轮询往下走。

现在我们改下。把NSLock改成我们的递归锁

NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];

然后我们继续走,这次就不会被锁死了,会一直到出现1为止。

这就是递归锁的神奇之处,因为我们是在一个线程里,所以不会因为我一直没解锁,还终止递归。


NSConditionLock 相关知识点:

  1. NSConditionLock 是锁,一旦一个线程获得锁,其他线程一定等待
  2. [xxxx lock]; 表示 xxx 期待获得锁,如果没有其他线程获得锁(不需要判断内部的condition) 那它能执行此行以下代码,如果已经有其他线程获得锁(可能是条件锁,或者无条件锁),则等待,直至其他线程解锁
  1. [xxx lockWhenCondition:A条件]; 表示如果没有其他线程获得该锁,但是该锁内部的condition不等于A条件,它依然不能获得锁,仍然等待。如果内部的condition等于A条件,并且没有其他线程获得该锁,则进入代码区,同时设置它获得该锁,其他任何线程都将等待它代码的完成,直至它解锁。
  1. [xxx unlockWithCondition:A条件]; 表示释放锁,同时把内部的condition设置为A条件

下面看个栗子


NSConditionLock *lock = [[NSConditionLock alloc] init];
NSMutableArray *products=[NSMutableArray array];
NSInteger HAS_DATA=1;
NSInteger NO_DATA=0;
// 线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
        while(1){
            [lock lockWhenCondition:NO_DATA];
            [products addObject:[[NSObject alloc] init]];
            NSLog(@"produceaproduct,总量:%zi",products.count);
            [lock unlockWithCondition:HAS_DATA];
            sleep(1);
        }
    });
 // 线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
        while(1){
            [lock lockWhenCondition:HAS_DATA];
            NSLog(@"waitforproduct");
            [products removeObjectAtIndex:0];
            NSLog(@"customeaproduct");
            [lock unlockWithCondition:NO_DATA];
        }
    });

解释下:

因为我们默认的没有给condition,所以是0,故能进入线程1,进入线程1后,到最后会用1的条件来让别人解锁。同时让自身的condition重置成1,这样做为了让线程2不在等待。这样就能顺利的让线程2接力,线程2在结束的时候又把球抛给线程1,这样1来2去,就不会死锁。

以上便是常用的锁的常用解释。这些都是线程锁。
下面还有一个进程锁,可以用来堵塞进程的,信号量

信号量的创建:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
这个参数必须是>=0不然这个semaphore就会返回null。
dispatch_semaphore_wait信号量-1,dispatch_semaphore_signal信号量+1.

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(@"yyy");
        [NSThread sleepForTimeInterval:5];
        dispatch_semaphore_signal(semaphore);
    });

// 线程2

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"xxxx");
        dispatch_semaphore_signal(semaphore);
    });

如果是semaphore创建的时候信号量是0的时候,谁也别想走了,全部挂起。

线程1里,进去就休眠5秒,在这期间,谁也不能run,全部挂起,直到5秒后,信号量+1后才都恢复生机。线程2也一样的逻辑。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容

  • 锁是一种同步机制,用于多线程环境中对资源访问的限制iOS中常见锁的性能对比图(摘自:ibireme): iOS锁的...
    LiLS阅读 1,514评论 0 6
  • 在平时的开发中经常使用到多线程,在使用多线程的过程中,难免会遇到资源竞争的问题,那我们怎么来避免出现这种问题那? ...
    IAMCJ阅读 3,092评论 2 25
  • 2016年国庆假期终于把此书过完,整理笔记和体会于此。 关于书名 书名源于俄罗斯的演员斯坦尼斯拉夫斯基创作的《演员...
    李剑飞的简书阅读 7,229评论 2 65
  • iOS线程安全的锁与性能对比 一、锁的基本使用方法 1.1、@synchronized 这是我们最熟悉的枷锁方式,...
    Jacky_Yang阅读 2,216评论 0 17
  • 在深邃而寂寥的人生旅途中,财米油盐的琐碎会轻易的敲碎壮丽的诗篇所勾勒的远方,夜半梦回的无奈又触摸到苟且的眼前所印证...
    一吻作别阅读 200评论 0 0