iOS 开发中的锁相关

加锁是实现线程同步方案很重要的一种方式,在iOS中,还是有很多种类型的锁,他们适用不同的场景,当然也存在不同的问题,以下就是各种锁的应用和注意点。


OSSpinLock
自旋锁,目前已经废弃,他叫自旋锁的原因就是因为他在等待加锁的时候,一直处于忙等状态,类似于
while(suo){
}
一直在运行中,判断锁的状态,它存在的问题就是优先级翻转,如果我们设置后进入的线程的优先级较高,那么系统会优先执行这个线程,内部加锁的线程就一直处于等待系统分配时间的状态,也就造成了死锁。
使用

#import <libkern/OSAtomic.h>
   OSSpinLock lock = OS_SPINLOCK_INIT;
   OSSpinLockLock(lock);
   OSSpinLockUnlock(lock);
   OSSpinLockTry(lock);

os_unfair_lock
这属于低级锁,在没事的时候处于睡眠状态等待,可以加锁,通过内核通知唤醒,可以代替OSSpinLock使用。

 #import <os/lock.h>
    os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
    os_unfair_lock_lock(&lock);
    os_unfair_lock_unlock(&lock);
    os_unfair_lock_trylock(&lock);

pthread_mutex
互斥锁,这是跨平台使用的一种锁,比较底层,iOS中很多面向对象的锁NSLock这些,都是封装的这种锁,这种锁,可以设置属性,变成递归锁(允许你同一条线程重复加锁)和条件条件锁。
先看递归锁

 //初始化锁属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, 2);  //这里的2 就是递归锁
    //初始化
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &attr);
    //尝试加锁
    pthread_mutex_trylock(&mutex);
    //加锁
    pthread_mutex_lock(&mutex);
    //解锁
    pthread_mutex_unlock(&mutex);
    
    //销毁锁和锁属性
    pthread_mutex_destroy(&mutex);
    pthread_mutexattr_destroy(&attr);

   pthread_mutex_trylock(&mutex); //不会阻塞,而是会继续执行
意思就是,当所被使用了,或者所没有初始化的时候,加锁失败,这个会返回一个int值,除了0都是加锁失败,然后继续执行。

     条件锁
     pthread_cond_t con;
    pthread_cond_init(&con, NULL);
   //等待
    pthread_cond_wait(&con, &mutex);
  //发出可以执行的信号
    pthread_cond_signal(&con);
 //所有等待整个信号的线程都可以执行了
    pthread_cond_broadcast(&con);

是不是很眼熟,可信号量很像

注意使用pthread_mutex,最后都要销毁

NSLock
普通锁,这个锁就是对pthread_mutex普通锁的封装,使用的API
就是

[lock lock]
[lock unLock]

NSRecursiveLock
看名字就知道了,递归锁,允许同一个线程不断加锁,是对pthread_mutex递归锁的封装

一般这种情况下,锁还没解开,你又来了,死锁,但是递归锁允许通一把锁重复加锁。
   NSRecursiveLock * recurlock = [[NSRecursiveLock alloc]init];
-(void)lock1{
    [recurlock lock];
    for (int i = 0; i < 10; i++) {
        [self lock1];
    }
    [recurlock unlock];

NSCondition
条件所,对pthread_mutex的条件锁的简单封装

- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;

NSConditionLock
是对pthread_mutex条件锁的进一步封装,可以设置具体的数字条件

- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

@synchronized
这也是对pthread_mutex递归锁的封装,使用起来比较简单

 @synchronized (<#token#>) {
        <#statements#>
    }

但是很多人都说他的性能较差,那么差在什么地方呢?加锁解锁使用的是pthread_mutex,性能不差,差的是寻找锁的过程,根据传入token的不同,生成不同的锁,锁存在一个全局map中,使用了拉链法拓展,所以找锁的过程是消耗性能的地方(另开一篇文章讲讲@synchronized底层的实现)。

其他的线程同步方案

atomic
在set get方法内部添加了自旋锁,保证线程同步,但是影响一定的性能

 // Atomic retain release world
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();
    id value = objc_retain(*slot);
    slotlock.unlock();

信号量
当我们设置信号量通过线程数量为1 的时候,也是能实现线程同步的。

以上都是一些线程同步的方案,大部分是锁的实现方式。

关于锁,我们看到有自旋锁、互斥锁、递归锁,他们的分类是怎么样的呢?
目前上边介绍的大类就是自旋锁和互斥锁;
自旋锁就是不断访问锁,询问锁是否可用,占用CPU资源。
互斥锁分为递归锁和非递归锁,递归锁允许同一条线程重复加锁,也就是同一条线程,只是对锁的引用计数++,还是会继续执行。
互斥锁维护一个队列,如果锁被使用,将线程加入队列,等待唤醒。

关于锁的性能,参考其他人的测试如下

  • OSSpinLock
  • dipatch_semaphore
  • prethad_mutex
  • NSLock
  • NSCondition
  • pthread_mutex(recursice)
  • NSRecuresiceLock
  • NSConditionLock
  • @synchronized

拓展一点其他,在多线程开发中,一般都是多读单写的要求;实际的场景,买票;查询有多少票的时候可以多条线程查,但是要改变票的数量的时候,只能有一个线程来改,并且改的时候,就不能查了。
实现这个功能,一般有 读写锁、栅栏函数等。

读写锁

读
 pthread_rwlock_rdlock(&_lock);
 pthread_rwlock_unlock(&_lock);
写
 pthread_rwlock_wrlock(&_lock);
 pthread_rwlock_unlock(&_lock);

栅栏函数

dispatch_barrier_async
他的实现原理,就是操作队列,当前任务block执行完之前,后续block 不会执行,dispatch_barrier_async前边的block会并发执行。

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