多线程-加锁

[大佬的理解各种锁]
(https://juejin.im/post/5a0a92996fb9a0451f307479)

自己总结的,要自己写呀,要不记不住啊..

一份数据被多个线程引用就会出现安全隐患


多线程操作.png
线程加锁后.png

1,iOS中的线程同步方案,分为自旋锁和互斥锁

1.1 OSSpinLock(自旋锁),

等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
目前已经不再安全,可能会出现优先级反转问题
如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁
需要导入头文件#import <libkern/OSAtomic.h>

//初始化
OSSpinLock lock = OS_SPINLOCK_INIT;
//尝试加锁,如果需要等待就不加锁,直接返回false,如果不需要等待加锁就返回true
bool result = OSSpinLockTry(&lock);
//加锁
OSSpinLockLock(&lock);
//解锁
OSSpinLockUnLock(&lock);

@property (nonatomic ,assign) OSSpinLock lock;

-(void)viewDidLoad

{

    [super viewDidLoad];

    self.lock = OS_SPIN_LOCK_INIT;

}

-(void)lockTest

{

//尝试加锁,解决优先级较高的线程先调用的问题,避免造成死锁

    if (OSSpinLockTry(&_lock)) {

    int oldticketsCount = self.ticketsCount ;

    sleep(.2);

    oldticketsCount--;

     self.ticketsCount =   oldticketsCount;

    //解锁

    OSSpinlockUnlock(_lock);        


     }

    //加锁

    OSSpinLockLock(&_lock)

    int oldticketsCount = self.ticketsCount ;

    sleep(.2);

    oldticketsCount--;

     self.ticketsCount =   oldticketsCount;

    //解锁

    OSSpinlockUnlock(_lock);        

}

1.2 os_unfair_lock

os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持
从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
需要导入头文件#import <os/lock.h>

//初始化
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
//尝试加锁
os_unfair_lock_trylock(&lock);
//加锁
os_fair_lock_lock(&lock);
//解锁
os_fair_lock_unlock(&lock);

1.3、pthread_mutex

1.3.1 常规锁

mutex叫做”互斥锁”,等待锁的线程会处于休眠状态
需要导入头文件#import <pthread.h>

//初始化锁的属性
pthread_mutexattr_t attr; //创建属性
pthread_mutexattr_init(&attr);//舒适化属性
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NOMAL);//设置属性类型
//初始化锁
pthread_metux_t mutex;
pthread_mutex_init(&mutex,&attr);
//尝试加锁
pthread_mutex_trylock(&mutex);
//加锁
pthread_mutex_lock(&mutex);
//解锁
pthread_mutex_unlock(&mutex);
//销毁资源
pthread_mutexattr_destroy(&attr);
pthread_mutex_destroy(&mutex);
//属性
@property (nonatomic , assign) pthread_mutex_t mutex;

-(void)viewDidLoad{

         //初始化属性
       // pthread_mutexattr_t   attr;//创建
       // pthread_mutexattr_init(&attr);//初始化
      //  pthread_mutexattr_settertype(&attr , PTHREAD_MUTEX_NORMAL); 
        
        //初始化互斥锁
        //    pthread_mutex_init(&_mutex , &attr);

       直接等同于
          pthread_mutex_init(&_mutex , NULL);

}

-(void)testMutex
{
     //尝试加锁
        pthread_mutex_trylock(&mutex);
    //加锁
      pthread_mutex_lock(&mutex);
   //解锁
      pthread_mutex_unlock(&mutex);

}

-(void)dealloc
{
 //销毁相关资源
 pthread_mutexattr_destory(&attr);
 pthread_mutex_destory(&mutex);       
}

1.3.2、递归锁

  //初始化属性
  pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
//初始化锁
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,&attr);

//销毁资源
pthread_mutexattr_destroy(&attr);
pthread_mutex_destroy(&mutex);

1.3.2、条件锁

//初始化锁
pthread_mutex_t mutex;
//MULL表示使用默认属性
pthread_mutex_init(&mutex,NULL);
//初始化条件
pthread_cond_t condition;
pthread_cond_init(&condition,NULL);
//等待条件(进入休眠,放开mutex锁,被唤醒后,再次对mutex进行加锁)
pthread_cond_wait(&condition,&mutex);

//激活一个等待该条件的线程
pthread_cond_signal(&condition,&mutex);

//激活所有等待该条件的线程
pthread_cond_broadcast(&condition);

//销毁资源
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&condition);

1.4、NSLock、NSRecursiveLock

NSLock是对mutex普通锁的封装

@interface NSLock : NSObject <NSLocking> {
-(BOOL)tryLock;
-(BOOL)lockBeforeDate:(NSDate *)limit;
}
@end
@protocol NSLocking
-(void)lock;
-(void)unlock
@end

//初始化锁
NSLock *lock = [[NSLock alloc]init];

NSRecursiveLock也是对mutex递归锁的封装,API和NSLock基本一致

1.5、NSCondition

NSCondition 是对mutex和cond的封装

@interface NSCondition : NSObject <NSLocking>{
-(void)wait;
-(BOOL)waitUntilDate:(NSDate *)limit;
-(void)signal;
-(void)broadcast;
}

1.6、NSConditionLock

NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值,

@interface NSConditionLock : NSObject <NSLocking>{

@property(readonly) NSInteger condition;
-(instancetype)initWithCondition:(NSInteger)condition;
-(BOOL)tryLock;
-(BOOL)tryLockWhenCondition:(NSInteger)condition;
-(void)unlockWithCondition:(NSInteger)condition;
-(BOOL)lockBeforeDate:(NSDate *)limit;
-(BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
@end
}

1.7、dispatch_semaphore

semaphore叫做"信号量";
信号量的初始值,可以用来控制线程并发访问的最大数量,
信号量的初始值为1,代表同时只允许一条线程访问资源,保证线程同步

//信号量的初始值
int value = 1;
//初始化信号量
dispath_semaphore_t semaphore = dispatch_semaphore_create(value);
//如果信号量的值<=0,当前线程就会进入休眠等待(直到信号量的值>0)
//如果信号量>0,就减1,然后往下执行后面的代码
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
//让信号量的值加一
disparch_semaphore_signal(semaphore);

1.8、dispatch_queue

直接使用GCD的串行队列,也是可以实现线程同步的

dispatch_queue_t queue = dispatch_queue_create("lock_queue",DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
    //任务
});

1.9、@synchronized

GNUstep是GNU计划的项目之一,它将Cocoa的OC库重新开源实现了一遍
源码地址:http://www.gnustep.org/resources/downloads.php
虽然GNUstep不是苹果官方源码,但还是具有一定的参考价值

@synchronized是对mutex递归锁的封装
源码查看:objc4中的objc-sync.mm文件
@synchronized(obj)内部会生成obj对应的递归锁,然后进行加锁、解锁操作

@synchronized(obj){
  //做任务
}

2、iOS线程同步方案性能比较

性能从高到低排序
os_unfair_lock
OSSpinLock
dispatch_semaphore
pthread_mutex
dispatch_queue(DISPATCH_QUEUE_SERIAL)
NSLock
NSCondition
pthread_mutex(recursive)
NSRecursiveLock
NSConditionLock
@synchronized

3、自旋锁和互斥锁比较

3.1、什么情况用自旋锁比较划算?

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

3.2、什么情况使用互斥锁比较划算?

预计线程等待锁的时间长,单核处理器,临界区有IO操作,
临界区代码复杂或者循环量大
临界区竞争非常激烈

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

推荐阅读更多精彩内容

  • 目录:1.为什么要线程安全2.多线程安全隐患分析3.多线程安全隐患的解决方案4.锁的分类-13种锁4.1.1OSS...
    二斤寂寞阅读 1,137评论 0 3
  • os_unfair_lock os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始...
    曹来东阅读 1,662评论 0 0
  • 锁是一种同步机制,用于多线程环境中对资源访问的限制iOS中常见锁的性能对比图(摘自:ibireme): iOS锁的...
    LiLS阅读 1,458评论 0 6
  • 一、简介:多线程在之前进行过一篇详细的基础博客 iOS多线程 二、多线程的基础知识回顾 1.1、iOS中的常见多线...
    IIronMan阅读 833评论 0 4
  • 你理解的多线程? iOS的多线程方案有哪几种?你更倾向于哪一种? pthread 􏼑􏴓􏴔跨平台 、使用难度大,手动...
    英雄出少年阅读 323评论 0 0