iOS 中几种常用的锁总结

理解:iOS开发中锁的实现原理 摘要 本文的目的不是介绍 iOS 中各种锁如何使用,一方面笔者没有大量的实战经验,另一方面这样的文章相当多,比如 iOS中保证线程安全的几种方式与性能对比、iOS 常见知识点(三):Lock。本文也不会详细介绍锁的具体实现原理,这会涉及到太多相关知识,笔者不敢误人子弟。 本文要做的就是简单的分析 iOS 开发中常见的几种锁如何实现,以及优缺点是什么,为什么会有性能上的差距,最终会简单的介绍锁的底层实现原理。水平有限,如果不慎有误,欢迎交流指正。同时建议读者在阅读本文以前,对 OC 中各种锁的使用方 阅读详情
  iOS锁介绍
多线程编程中,应该尽量避免资源在线程之间共享,以减少线程间的相互作用。 但是总是有多个线程相互干扰的情况(如多个线程访问一个资源)。在线程必须交互的情况下,就需要一些同步工具,来确保当它们交互的时候是安全的。
锁是线程编程同步工具的基础。iOS开发中常用的锁有如下几种:
1、@synchronized
2、NSLock 对象锁
3、NSRecursiveLock 递归锁
4、NSConditionLock 条件锁
5、pthread_mutex 互斥锁(C语言)
6、dispatch_semaphore 信号量实现加锁(GCD)
7、 OSSpinLock (暂不建议使用)
下图是它们的性能对比:


  @synchronized 关键字加锁 互斥锁,性能较差不推荐使用
@synchronized(这里添加一个OC对象,一般使用self) {
       这里写要加锁的代码
  }
 注意点
   1.加锁的代码尽量少
   2.添加的OC对象必须在多个线程中都是同一对象
    3.优点是不需要显式的创建锁对象,便可以实现锁的机制。
    4. @synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
下面通过 卖票的例子 展示使用
//设置票的数量为5
    _tickets = 5;
    
    //线程1
    dispatch_async(self.concurrentQueue, ^{
        [self saleTickets];
    });
    
    //线程2
    dispatch_async(self.concurrentQueue, ^{
        [self saleTickets];
    });

- (void)saleTickets
{
    while (1) {
        @synchronized(self) {
            [NSThread sleepForTimeInterval:1];
            if (_tickets > 0) {
                _tickets--;
                NSLog(@"剩余票数= %ld, Thread:%@",_tickets,[NSThread currentThread]);
            } else {
                NSLog(@"票卖完了  Thread:%@",[NSThread currentThread]);
                break;
            }
        }
    }
}
  NSLock 互斥锁 不能多次调用 lock方法,会造成死锁
在Cocoa程序中NSLock中实现了一个简单的互斥锁。
所有锁(包括NSLock)的接口实际上都是通过NSLocking协议定义的,它定义了lock和unlock方法。你使用这些方法来获取和释放该锁。
NSLock类还增加了tryLock和lockBeforeDate:方法。
tryLock试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程,相反,它只是返回NO。
lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回NO)。
还是卖票的例子
//设置票的数量为5
    _tickets = 5;
    
    //创建锁
    _mutexLock = [[NSLock alloc] init];
    
    //线程1
    dispatch_async(self.concurrentQueue, ^{
        [self saleTickets];
    });
    
    //线程2
    dispatch_async(self.concurrentQueue, ^{
        [self saleTickets];
    });

- (void)saleTickets
{

    while (1) {
        [NSThread sleepForTimeInterval:1];
        //加锁
        [_mutexLock lock];
        if (_tickets > 0) {
            _tickets--;
            NSLog(@"剩余票数= %ld, Thread:%@",_tickets,[NSThread currentThread]);        
        } else {
            NSLog(@"票卖完了  Thread:%@",[NSThread currentThread]);
            break;
        }
        //解锁
        [_mutexLock unlock];
    }
}
  NSRecursiveLock 递归锁
使用锁最容易犯的一个错误就是在递归或循环中造成死锁
如下代码中,因为在线程1中的递归block中,锁会被多次的lock,所以自己也被阻塞了
//创建锁
    _mutexLock = [[NSLock alloc]init];
  
    //线程1
    dispatch_async(self.concurrentQueue, ^{
        static void(^TestMethod)(int);
        TestMethod = ^(int value)
        {
            [_mutexLock lock];
            if (value > 0)
            {
                [NSThread sleepForTimeInterval:1];
                TestMethod(value--);
            }
            [_mutexLock unlock];
        };
        
        TestMethod(5);
    });
此处将NSLock换成NSRecursiveLock,便可解决问题。
NSRecursiveLock类定义的锁可以在同一线程多次lock,而不会造成死锁。
递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操作。
只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。
//创建锁
    _rsLock = [[NSRecursiveLock alloc] init];
    
   //线程1
    dispatch_async(self.concurrentQueue, ^{
        static void(^TestMethod)(int);
        TestMethod = ^(int value)
        {
            [_rsLock lock];
            if (value > 0)
            {
                [NSThread sleepForTimeInterval:1];
                TestMethod(value--);
            }
            [_rsLock unlock];
        };
        
        TestMethod(5);
    });
  NSConditionLock 条件锁
条件锁,一个线程获得了锁,其它线程等待。
[xxxx lock]; 
表示 xxx 期待获得锁,如果没有其他线程获得锁(不需要判断内部的condition) 那它能执行此行以下代码,如果已经有其他线程获得锁(可能是条件锁,或者无条件锁),则等待,直至其他线程解锁
[xxx lockWhenCondition:A条件]; 
表示如果没有其他线程获得该锁,但是该锁内部的condition不等于A条件,它依然不能获得锁,仍然等待。如果内部的condition等于A条件,并且没有其他线程获得该锁,则进入代码区,同时设置它获得该锁,其他任何线程都将等待它代码的完成,直至它解锁。
[xxx unlockWithCondition:A条件]; 
表示释放锁,同时把内部的condition设置为A条件
看代码与介绍
//主线程中
    NSConditionLock *theLock = [[NSConditionLock alloc] init];
    
    //线程1
    dispatch_async(self.concurrentQueue, ^{
        for (int i=0;i<=3;i++)
        {
            [theLock lock];
            NSLog(@"thread1:%d",i);
            sleep(1);
            [theLock unlockWithCondition:i];
        }
    });
    
    //线程2
    dispatch_async(self.concurrentQueue, ^{
        [theLock lockWhenCondition:2];
        NSLog(@"thread2");
        [theLock unlock];
    });
在线程1中的加锁使用了lock,是不需要条件的,所以顺利的就锁住了。
unlockWithCondition:在开锁的同时设置了一个整型的条件 2 。
线程2则需要一把被标识为2的钥匙,所以当线程1循环到 i = 2 时,线程2的任务才执行。

NSConditionLock也跟其它的锁一样,是需要lock与unlock对应的,只是lock,lockWhenCondition:与unlock,unlockWithCondition:是可以随意组合的,当然这是与你的需求相关的。
  pthread_mutex 互斥锁
__block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    
    //线程1
    dispatch_async(self.concurrentQueue), ^{
        pthread_mutex_lock(&mutex);
        NSLog(@"任务1");
        sleep(2);
        pthread_mutex_unlock(&mutex);
    });
    
    //线程2
    dispatch_async(self.concurrentQueue), ^{
        sleep(1);
        pthread_mutex_lock(&mutex);
        NSLog(@"任务2");
        pthread_mutex_unlock(&mutex);
    });
  dispatch_semaphore 信号量实现加锁
GCD中也已经提供了一种信号机制,使用它我们也可以来构建一把”锁”(从本质意义上讲,信号量与锁是有区别。):
// 创建信号量
    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);
    });
  OSSpinLock
OSSpinLock 在图1.1 中显示的效率最高
//设置票的数量为5
    _tickets = 5;
    //创建锁
    _pinLock = OS_SPINLOCK_INIT;
    //线程1
    dispatch_async(self.concurrentQueue, ^{
        [self saleTickets];
    });
    //线程2
    dispatch_async(self.concurrentQueue, ^{
        [self saleTickets];
    });

- (void)saleTickets {
    
        while (1) {
            [NSThread sleepForTimeInterval:1];
            //加锁
            OSSpinLockLock(&_pinLock);
            
            if (_tickets > 0) {
                _tickets--;
                NSLog(@"剩余票数= %ld, Thread:%@",_tickets,[NSThread currentThread]);
                
            } else {
                NSLog(@"票卖完了  Thread:%@",[NSThread currentThread]);
                break;
            }
            //解锁
            OSSpinLockUnlock(&_pinLock);
        }

}
版权所有:半 饱 开发专栏
版本转载:http://blog.youkuaiyun.com/banbaodevelop
ps:如有转载请加以上信息

谈谈iOS中的几种锁 主要介绍了谈谈iOS中的几种锁,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。 立即下载

相关推荐

散户逆袭神器:用通达信DIY指数发现下一个光伏储能(附龙头股筛选模板)

本文详细介绍了如何利用通达信软件的自定义指数功能,构建个人专属的行业监控工具,以发现类似光伏储能这样的潜力赛道。文章提供了从零开始的指数编制步骤、核心的龙头股筛选模板,以及五个关键的数据校验技巧,帮助散户投资者实现机构级的行业分析与机会挖掘,有效提升投资决策能力。

w3x4y的博客 482

iOS多线程---常用的几种锁

我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,这就是锁。线程安全措施有:atomic、@synchronize(对象)、NSLock、NSRecursiveLock递归锁、NSCoditionLock(条件锁)、NSCondition、dispatch_semaphore、OSSpinLock(自旋锁,已弃用)、os_unfair_lock、pthread_mutex 、dispatch_once。

旭日的博客 1248

S32K344 Bootloader实战:一个按键实现从Boot到App的无缝跳转(附完整代码)

本文详细介绍了基于NXP S32K344微控制器的Bootloader开发实战,重点解析如何通过一个硬件按键实现从Boot到App的可靠跳转。内容涵盖内存分区规划、中断向量表重映射、外设初始状态管理等核心要素,并提供了完整的代码示例和调试技巧,适用于汽车电子和工业控制等高可靠性应用场景。

weixin_29192365的博客 307

iOS 开发中的八种锁(Lock)

锁之前的性能的图表: lock_benchmark.png 发现除了@synchronized 用过,其他的都陌生的很,可以说完全不知道啥玩意儿~ 于是怀着惭愧的心情赶紧把这些锁学习了下,废话不多说,我们开始: 锁 是什么意思? 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块

努力,可能成功!放弃,注定失败! 1万+

Vitis开发环境下的双核ARM通信:Hello World背后的AMP架构解析

本文深入解析了Vitis开发环境下ZYNQ双核ARM Cortex-A9处理器的AMP架构与通信机制。通过详细的硬件配置、内存分配和核间通信实现步骤,展示了如何构建高效的双核Hello World系统,为嵌入式系统开发者提供了实用的开发指南和性能优化技巧。

weixin_29162439的博客 217

Unity通用Buff系统,Buff编辑器(1,理论篇)(技能系统之Buff篇)

逻辑层根据游戏的规则和设计,控制Buff的生命周期、影响目标对象的属性或行为,以及处理Buff的交互和冲突。Buff堆叠和冲突:有些游戏中允许同类型的Buff叠加,以增加效果的强度,而有些游戏中可能不允许Buff叠加,只能由更强力的Buff来覆盖较弱的Buff。灵活个性化:每个游戏对象拥有自己的BuffManager,可以实现个体对象的独特Buff效果,增加游戏的多样性和个性化。自由控制:每个对象独立管理自己的Buff,可以自由地激活、更新和移除Buff效果,提供更精细的控制和逻辑实现。

u010082265的博客 4693

iOS 中常见的几种锁-代码示例

iOS 中常见的几种锁介绍-示例 常用的各类锁性能比较 文中Demo 均实现在 XWInterviewDemos 1. iOS中的互斥锁 在编程中,引入对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象。 1.1 @synchronized (self) - (void)lock1 { @syn...

weixin_34366546的博客 340

零代码进行单细胞数据全流程分析教程

我开发的本地电脑无限使用无限分析作图的生信零代码一键分析电脑软件神器OmicsTools 软件在github上的zihaoxingstudy1/OmicsTools仓库 中,大家可以下载安装OmicsTools进行各种生信分析和可视化作图。

qq_40073899的博客 3617

[iOS开发]iOS中的相关锁

iOS相关锁学习

weixin_52192405的博客 1190

TMS320F280049C 学习笔记21 交叉开关 Crossbar (X-BAR)

简单介绍了X-BAR。

whyorwhnt的专栏 2万+

Python爬虫实战:利用Playwright+Asyncio高效获取淘宝商品价格变化曲线

本文将详细介绍如何使用Python最新技术栈(Playwright+Asyncio)构建一个高效的淘宝商品价格监控爬虫系统。我们将从爬虫基础知识讲起,逐步深入到反爬应对策略、数据存储与分析,最终实现价格变化曲线的可视化展示。文章包含完整的代码实现和详细的技术解析,适合中高级Python开发者学习参考。关键词:Python爬虫、Playwright、Asyncio、淘宝价格监控、数据可视化支持多浏览器(Chromium, Firefox, WebKit)更快的执行速度更丰富的API。

2201_76125261的博客 244

近万字深入讲解iOS常见锁及线程安全

上述学习的各种常见的线程锁,都是为了更好地管理和调配线程,而在开发中我们往往不可避免地采用多线程并发,这虽然很便利但是存在的巨大的安全隐患。这段代码因为多线程并发同时修改同一个变量,导致可能的结果是测试下来可能会是打印了两个 2,这就不符合我们的预期了,明明第一个传入的是 “1”,打印结果却为 2。这种情况称为资源竞争,两个线程可能同时操作user对象,实际上,除了结果不符合预期外,还可能出现一个经典的崩溃,这是因为让两个线程尝试同时操作同一个内存地址导致的。

ScheenDuan的博客 1970

9篇6章7节:SEER 数据库的2025年数据变量多条件组合选择(2026年版)

软件中的病例筛选功能通过CaseSelection界面实现精准研究队列构建。该界面允许用户通过变量选择(Variable)、运算符定义(Operator)和取值设定(Values)三步操作创建筛选条件,支持种族、分期等关键变量的多条件组合。

MD Code 1454

iOS常用的几种锁详解以及用法

两种锁的加锁原理特殊的互斥锁,加了递归功能ios中常见的几种锁包括OSSpinLock、信号量(Semaphore)、pthread_mutex、NSLock、NSCondition、NSConditionLock、pthread_mutex(recursive)、NSRecursiveLock、synchronized如下所示,测试锁性能的案例图(实际可能会略有偏差): 由于OSSpinLock目前已经不再安全,存在bug,官方已放弃,iOS10之后os_unfair_lock取代OSSpinLock。基

wywinstonwy的专栏 3939

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

iOS中常用的几种锁

自旋锁 NSSpinLock ,它现在被废弃了,不能使用了,它是有缺陷的,会造成死锁。当低优先级线程访问了锁并执行了任务,这时恰好高的优先级线程也访问了锁,因为它的优先级较高,所以要优先执行任务,所以它会不停的访问该锁,并使得cpu大部分都用来访问该锁忙等了,造成低优先级的线程没有足够的cpu时机来执行任务,这样造成了死锁。 互斥锁 p_thread_mutex,NSLock,@synthron...

qq_17190231的博客 1676

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

IOS的几种锁 C++

1.互斥锁 互斥锁在同一时刻只允许一个线程访问资源。 #include <pthread.h> pthread_mutex_t mutex; pthread_mutex_init(&mutex,NULL);//初始化 或者这种方式初始化: pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; 对锁变量进行加锁的方式如下: pt...

qq_36415932的博客 203

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

iOS - 线程中常见的几种锁

线程锁主要是用来解决“共享资源”的问题,实际开发中或多或少的都会用到各类线程锁,为了线程的安全我们有必要了解常见的几种锁,下面是本人查看一些大牛的博客然后整理的内容,加上自己的一些见解,水平有限,如果不慎有误,欢迎交流指正。 常见锁列举 自旋锁(OSSPinLock、os_unfair_lock) 互斥锁(pthread_mutex_t、NSLock、@synthronized) 递归锁(pth...

SSY_1992的博客 2108

ios nslog 例子_iOS 中常见的几种锁-代码示例

常用的各类锁性能比较1. iOS中的互斥锁在编程中,引入对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象。1.1 @synchronized (self)-(void)lock1{@synchronized(self){//加锁操作}}1.2 NSLock-(void)lock2{NSLock...

weixin_39984201的博客 108

iOS的锁

性能从高到低大致排序(不同场景有差异):->OSSpinLock(已废弃) ->->->NSLock->->->->选择建议追求极致性能:使用(iOS 10+)或。需要递归:使用或。简单易用,不关心性能:使用。控制并发数:使用。读写分离:使用。理解各种锁的特性和适用场景,是编写高效、安全的多线程代码的关键。

m0_49556278的博客 920

iOS开发之用到的几种锁整理

1. iOS中的互斥锁 在编程中,引入对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象。 1.1 @synchronized (self) -(void)lock1{@synchronized(self){//加锁操作}} 1.2 NSLock -...

weixin_34410662的博客 116

iOS 开发中的几种锁

ios开发中的几种锁(一)ios开发中的几种锁(二)ios开发中的几种锁(三)ios开发中的几种锁(四) ...

weixin_34290631的博客 130

ios 各种锁的使用性能比较

iOS开发中常用的锁有如下几种 来比较一下遇到加锁的情况: 1. @synchronized 关键字加锁 2. NSLock对象锁3. NSCondition4. NSConditionLock 条件锁5. NSRecursiveLock 递归锁6. pthread_mutex 互斥锁(C语言)7. dispatch_semaphore 信号量实现加锁(GCD) 8. O...

weixin_34242331的博客 179
上一篇: 有关UIViewController与UIView的初始化创建
半_饱
博客等级 码龄12年 6粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值