解决线程同步的方案汇总总结

这是一篇继上一篇继续介绍多线程同步的博客.(你了解多线程自旋锁、互斥锁、递归锁等锁吗?)

GNUstep介绍

再介绍其他锁之前我们先看一个其他的知识点.我们知道在Foundation框架下,苹果公开的源码只有NSObject,而我们想知道的NSString、NSArray、NSRunLoop、NSThread等等都是没有给源码的.只给了NSObject的部分实现,如果我们确实想看这些源码的话.通过汇编,打断点一步一步看,这样也是可以看到的,但是这样就有点麻烦,要会汇编语言,而且还要一点一点的调试才能知道.所以这里给大家介绍另一个方案,叫做:GNUstep.

GNUstep是GNU计划的项目之一,GNU计划就是一个软件计划,就是希望能够开源非常非常多的源码,希望都是自由的,我们可以认为这个计划就是做了非常非常多的开源项目.GNUstep就是GNU计划之一,它将Cocoa的OC库重新开源实现了一遍.就是虽然苹果的NSString、NSArray、NSRunLoop、NSThread等等都是没有开源的,GNUstep就是把它重新实现了一遍并且开源了.

GNUstep源码下载地址(建议下载 Base1.26.0版本)

虽然GNUstep不是苹果官方源码,但还是具有一定的参考价值,它里面的实现和苹果源码的实现是非常接近的.请看下面的截图:

它具有一定的参考价值,对于我们后面理解一些东西有很重要的作用.

接下来我们看看条件锁

pthread_mutex (条件锁)

对于mutex的互斥锁、递归锁我们都是很清楚的了,接下来我们直接看看条件锁.首先看一下我的需求是什么样,如下图:

我的业务需求是希望:如果dataMuArr.count==0的时候,我不删除,等dataMuArr有数据了我再去删除.那这时候,我们就可以用条件锁,请看下面:

从log输出,可以看出,条件锁确实可以解决这种需求.而且我们可以发现pthread_cond_wait在休眠的时候是解锁了,所以add方法才能继续执行,被唤醒的时候又加锁,所以加锁和解锁是还是成对出现的.还有个补充点就是:目前是一个线程在等待,如果是多个线程在等待,我们就用pthread_cond_broadcast(&_cond)即可,broadcast是广播的意思,所以很容易理解,大家可以试试.

NSLock、NSRecursiveLock、NSCondition详解

NSLock:它是对pthread_mutex普通锁的封装,一看就是oc对象,使用起来更加面向对象,我们看下用法

- (BOOL)tryLock;//尝试加锁

- (BOOL)lockBeforeDate:(NSDate*)limit; //在这个时间之前,如果我能等到这把锁解锁我就等,否则就不等

- (void)lock;  //加锁

- (void)unlock;//解锁

主要是上面这四个,我们直接用吧,上面写得都很清晰:

上面结果很清晰,没有问题,用法也是非常的简单.这里还有个注意点,我们可以用我上一个博客的知识点可以查看汇编调用过程,你会发现如下

因为这个过程还要找缓存,找方法,全是消息机制那些,知道这些有什么用呢?这个给我们对比线程同步的性能方面提供了参考,它的性能相对来说,肯定没有pthread_mutex效率高,因为它多执行了很多代码,这个很清晰吧.

如果我们通过打断点也是能找到NSLock的实现,具体调用等等,但是发现很麻烦,这时候我们就用上面说的GNUstep里面查找一下,如下图:

这里很明显可以看出是对pthread_mutex普通锁的一个封装.

NSRecursiveLock:它是对pthread_mutex递归锁的封装,它基本和上面的NSLock一样的,几乎是一样的,我们直接看一下用法,稍微过一下:

NSCondition:它是对pthread_mutex和cont的封装,也就是上面的条件锁,我们也看下用法:

- (void)wait;//等待

- (BOOL)waitUntilDate:(NSDate*)limit;//在这个时间之前,如果我能等到这把锁解锁我就等,否则就不等

- (void)signal;//信号

- (void)broadcast;//广播

- (void)lock;  //加锁

- (void)unlock;//解锁

我直接演示一下用法即可,你可以用条件锁,也可以普通锁.我就把前面那个演示一下:

NSConditionLock详解

NSConditionLock:它是对NSCondition的进一步封装,可以设置具体的条件值,以前的锁都是等待什么,这个是可以设置具体的值

这时候如果我们把初始化条件置为其他的话,程序就会一直休眠,不会有任何打印.用这个锁,我们就可以达到控制多线程的执行顺序,无论多少个,我们都能控制.这个也是很明确,就不细说了

dispatch_queue (DISPATCH_QUEUE_SERIAL)

直接使用GCD的串行队列,也是可以实现线程同步的.我们不能想到线程同步,就想到锁,我们要知道线程同步的本质是什么,就是多条线程抢占同一个资源,所以串行队列也是可以解决线程同步的问题.比如我们就拿卖票来说.

dispatch_semaphore_t详解

dispatch_semaphore_t叫做"信号量"

信号量的初始值,可以用来控制线程并发访问的最大数量.如果我们最大数量设置1,那就是能达到线程同步的目的,现在我们先去看一下怎么使用

dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER):如果信号量的值是>0,就让信号量的值减1,然后继续往下执行代码...直到当信号量的值是0的时候,这时候就会休眠等待.首先看你传的时间,如果是now就立即执行,这里传的DISPATCH_TIME_FOREVER就不受时间这个条件限制了,直到当信号量的值>0才会唤起休眠,继续执行.

dispatch_semaphore_signal(self.semaphore):就是让信号量的值+1,只要变成1就会唤起之前的等待,就这样重复执行.

所以我们之前的代码,我们只要把信号量的值设置为1就可以做到线程同步,这里大家可以自己尝试.

@synchronized详解

相信很多都见过这个关键字

@synchronized它是对pthread_mutex递归锁的一个封装,我们参考一下GNUstep去参考一下源码.

它是在写法上最简单的,这里我们先看一下怎么使用:

写法非常简单,也是能解决线程同步. 这里的 @synchronized (self) 里面的self跟每个锁是一一对应的,我们可以理解就是self是key,这个锁就是value,就是存在字典中(可以由GNUstep去参考得知).所以如果是同一锁,@synchronized (self)这里的self对象必须是同一个对象.

说了这么多,上面的都是常用的方案.,当然还有其他方案,

线程同步总结:

1.同步方案性能优化对比:

这里是整理了一个由高到低的排序,也是测出来的,供大家参考:

os_unfair_lock (只支持iOS10以后)

OSSpinLock (不建议使用,iOS10以后弃用)

dispatch_semaphore_t

pthread_mutex 

dispatch_queue (DISPATCH_QUEUE_SERIAL)

NSLock

NSCondition

pthread_mutex (recursive)

NSRecursiveLock

NSConditionLock

@synchronized

所以推荐使用dispatch_semaphore_t和pthread_mutex ,初始化代码多的话,可以定义成宏.

2.自旋锁和互斥锁的对比

(虽然自旋锁现在已经不用了,因为只有一个还是废弃的,但是有时候面试喜欢问,所以这里我们还是说下)

一、什么时候用自旋锁比较划算?

预计线程的等待时间较短;加锁的代码(临界区)经常被调用,但竞争情况很少发生;CPU资源不紧张;多核处理器

二、什么时候用互斥锁比较划算?

预计线程等待时间较长;单核处理器;临界区由IO操作;临界区代码复杂或者循环量大.

接下来我会继续努力编写其他博客,您的支持就是我最大的动力!

如果觉得我写得对您有所帮助,请点赞关注我,我会持续更新😄

感谢支持🙏🙏🙏!

我是GDCoder,我们下期见!

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

推荐阅读更多精彩内容