首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Objective 锁

Objective 锁

作者头像
老沙
发布于 2019-09-28 05:19:31
发布于 2019-09-28 05:19:31
70200
代码可运行
举报
文章被收录于专栏:老沙课堂老沙课堂
运行总次数:0
代码可运行

加锁

线程安全隐患解决方案

解决方案 使用线程同步技术(按照预定的先后次序进行)

1、OSSpinLock 自旋锁 ( heigh-leve Lock、自旋锁)

#import "<libkern/OSAtomic.h>"


代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OSSpinLock _lock = OS_SPINLOCK_INIT;
 OSSpinLockLock(&_lock);
 OSSpinLockUnlock(&_lock);
 OSSpinLockTry(&_lock); //尝试加锁 如果不能加锁 返回No
复制代码
  • 因为是自旋锁( busy-wait) 所以一直cpu占用资源,线程不会休眠,一直等待,所以效率最高。
存在的问题
  • ios10之后过期
  • 优先级反转

由于锁是自旋锁,线程不会休眠,所以当低优先级线程先对操作进行Lock造作后,CPU调度高优先级线程造作,由于低优先级别UnLock就调用高优先级线程。高优先级无法处理该操作,而高优先级线程一直调用CPU资源, 系统等待高优先级线程执行完毕后才给低优先级线程资源。

高优先级线程等待低优先级线程Unlock。低优先级线程等待CPU资源调度。造成类似死锁 导致锁无法释放。相互等待

2、os_unfair_lock (low-level Lock、互斥锁 )

import <os.lock.h>

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
os_unfair_lock _lock = OS_UNFAIR_LOCK_INIT;
os_unfair_lock_lock(&_lock);
os_unfair_lock_unlock(&_lock);
os_unfair_lock_trylock(&_lock);//尝试加锁 如果不能加锁 返回No
复制代码
  • ios10之后支持
3、ptheard_mutex (low-level Lock、互斥锁)

#import"pthread.h"

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    pthread_mutexattr_t attr = {0};
    pthread_mutexattr_init(&attr);
		//设置锁的描述  PTHREAD_MUTEX_DEFAULT为一般互斥锁  PTHREAD_MUTEX_RECURSIVE为递归锁
		//pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE为递归锁); //递归锁
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    pthread_mutex_init(mutex, &attr);
		//释放  防止内存泄漏
    pthread_mutexattr_destroy(&attr);
复制代码
1、递归锁 PTHREAD_MUTEX_RECURSIVE

根据参数 attr PTHREAD_MUTEX_RECURSIVE 递归锁

PTHREAD_MUTEX_RECURSIVE :允许同一个线程 重复加锁。

2、条件 condition

线程激活信号 不一定会马上执行 先等上一次操作unlock

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 创建锁
- (void) __initLock:(pthread_mutex_t *) mutex {
    pthread_mutexattr_t attr = {0};
    pthread_mutexattr_init(&attr);
	  //互斥锁
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    pthread_mutex_init(mutex, &attr);
    pthread_mutexattr_destroy(&attr);
    
    pthread_condattr_t condAtt={0};
	  // 创建条件
    pthread_cond_init(&_condition, &condAtt);
    pthread_condattr_destroy(&condAtt);
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        [self __initLock:&_lock];
        
        
       dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            [self test2];
        });
        dispatch_async(queue, ^{
            sleep(2);
            [self test1];
            
        });
    }
    return self;
}
- (void)test1 {
    NSLog(@"%@",[NSThread currentThread]);
  	// lock
    pthread_mutex_lock(&_lock);
    NSLog(@"1");
	  //对condition发送信号
    pthread_cond_signal( &_condition);
	  NSLog(@"3");
	  //unlock
    pthread_mutex_unlock(&_lock);
	  NSLog(@"4");
}

- (void)test2 {
    NSLog(@"%@",[NSThread currentThread]);
  	// lock
    pthread_mutex_lock(&_lock);
  	// 等待condition发送信号
    pthread_cond_wait(&_condition, &_lock);
    NSLog(@"2");
  	//unlock
    pthread_mutex_unlock(&_lock);
}

复制代码

输出结果为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2019-09-03 14:55:49.650729+0800 GCD[1918:36391522] 1
2019-09-03 14:55:49.650896+0800 GCD[1918:36391522] 3
2019-09-03 14:55:49.651025+0800 GCD[1918:36391522] 4
2019-09-03 14:55:49.651031+0800 GCD[1918:36391523] 2
复制代码

上述代码 无论test1 和test2谁先调用 test2 依赖于test1的调用 只有当test1中执行 pthread_cond_signal( &_condition); test2中才会继续执行, 执行步骤为:

  1. Test2
  2. Test2 中lock pthread_mutex_lock(&_lock);
  3. 等待condition发送信号pthread_cond_wait(&_condition, &_lock); 此时unlock锁 并且线程休眠
  4. 2s后执行Test1
  5. Test1 中lock pthread_mutex_lock(&_lock);
  6. 输出1
  7. //对condition发送信号 pthread_cond_signal( &_condition); test2线程被激活
  8. 输出3
  9. Test1中解锁unlock
  10. Test2 执行lock操作中继续执行 输出2
  11. test2中解锁
  • 8-9 和10-11是同时进行
  • condition 不仅可以发送信号signal 还可以发送广播 pthread_cond_boradcast 激活所有pthread_cond_wait
注意点
  1. 使用condition的时候 不要使用同一个线程调用wait和signal 因为线程调度万wait的时候为休眠状态,无法执行signal 可以试试上面的代码 把并发队列换成串行队列试一下。
  2. 结构体初始化只能直接初始化 如下图所示
4、NSLock

NSLock是对mutex PTHREAD_MUTEX_DEFAULT 普通锁的封装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)lock;// 加锁
- (void)unlock;//解锁
- (BOOL)tryLock;// 尝试是否可以加锁 如果可以 直接加锁返回YES
- (BOOL)lockBeforeDate:(NSDate *)limit; //在一定时间内是否可以加锁 如果可以 直接加锁返回YES
复制代码
5、NSRecursiveLock

NSLock是对mutex PTHREAD_MUTEX_RECURSIVE递归锁的封装

API和NSLock一样

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)lock;// 加锁
- (void)unlock;//解锁
- (BOOL)tryLock;// 尝试是否可以加锁 如果可以 直接加锁返回YES
- (BOOL)lockBeforeDate:(NSDate *)limit; //在一定时间内是否可以加锁 如果可以 直接加锁返回YES
复制代码
6、NSCondition

NSCondition是对mutex和cond的封装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//用法和mutex condtion 一样  可以参考上面代码
- (void)lock;// 加锁
- (void)unlock;//解锁
- (void)wait;//等待
- (BOOL)waitUntilDate:(NSDate *)limit; //等待多久  如果超时就不等了 就直接执行
- (void)signal; // 信号量
- (void)broadcast; //广播
复制代码
7、NSConditionLock

NSConditionLock是对NSCondition的封装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)lock;// 加锁
- (void)unlock;//解锁
- (void)lockWhenCondition:(NSInteger)condition; //休眠 直到符合conditon后  激活并lock
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition; // 解锁 修改condtion的值
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
复制代码
8、Dispatch_semaphore

Dispatch_semaphore 可以控制线程的个数 当控制线程个数为1的时候 能确保同时只有1条线程去访问,已达到确保线程安全的目的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

// 如果信号量<=0 当前线程就会键入休眠状态 知道信号量的值>0
// 如果信号值>0 就-1 然后执行下面代码
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
[super __saleTicket];
// 信号量+1
dispatch_semaphore_signal(_semaphore);
复制代码
9、dispatch_quueue(DISPATCH_QUQUQ_SERIAL)

串行队列,当在一个串行队列执行的时候,只有一个线程,能确保线程安全

10、@synchronised

以前:对mutex递归锁的封装

现在:os_unfair_recursive_lock的封装

首先打开断点汇编模式

obj4源码中objc_sync.mm

底层存储 hash表 key :传进去的对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class recursive_mutex_tt : nocopy_t {
    os_unfair_recursive_lock mLock;
	  ...
}
using recursive_mutex_t = recursive_mutex_tt<LOCKDEBUG>;

typedef struct alignas(CacheLineSize) SyncData {
    struct SyncData* nextData;
    DisguisedPtr<objc_object> object;
    int32_t threadCount;  // number of THREADS using this block
    recursive_mutex_t mutex;
} SyncData;

int objc_sync_enter(id obj)
{
    int result = OBJC_SYNC_SUCCESS;

    if (obj) {
        SyncData* data = id2data(obj, ACQUIRE);
        assert(data);
        data->mutex.lock();
    } else {
        // @synchronized(nil) does nothing
        if (DebugNilSync) {
            _objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
        }
        objc_sync_nil();
    }

    return result;
}

复制代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int objc_sync_exit(id obj)
{
    int result = OBJC_SYNC_SUCCESS;
    
    if (obj) {
        SyncData* data = id2data(obj, RELEASE);
        if (!data) {
            result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
        } else {
            bool okay = data->mutex.tryUnlock();
            if (!okay) {
                result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
            }
        }
    } else {
        // @synchronized(nil) does nothing
    }
	

    return result;
}
复制代码

至于耗时,测的时候每次都不太一样,大家自己测一下吧~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老沙说点事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
​iOS线程锁#### 一:十种线程锁
测试中效率最高的锁, 不过经YYKit作者确认, OSSpinLock已经不再线程安全,OSSpinLock有潜在的优先级反转问题
花落花相惜
2021/11/21
1.2K0
阿里、字节:一套高效的iOS面试题( 多线程 GCD底层原理篇)
dispatch_group_create() + dispatch_group_wait()
会写bug的程序员
2020/06/18
5K0
阿里、字节:一套高效的iOS面试题( 多线程 GCD底层原理篇)
iOS_多线程五:基础的9种锁,扩展12种使用
解锁时,如果有1个以上的线程阻塞,那么所有该锁上的线程变为就绪状态,第一个就绪的加锁,其他的又进入休眠。
mikimo
2022/07/20
1K0
iOS_多线程五:基础的9种锁,扩展12种使用
iOS底层 - @synchronized(上)
IOS中的锁是比较困扰大家的一个问题,知道有锁这么个东西,但是却不常用。今天带大家一起走进锁的底层世界。
CC老师
2022/01/11
6220
iOS底层 - @synchronized(上)
OC底层探索24-synchronize锁的原理OC底层探索24-synchronize锁的原理
所有底层的探索都需要一个切入点,像这样的代码段除了堆栈的方式,还有clang、查看汇编的方式。
用户8893176
2021/08/09
6720
OC底层探索24-synchronize锁的原理OC底层探索24-synchronize锁的原理
iOS中的常用一些锁
我们在多线程编程中常常会使用一些锁来保证程序的线程安全,这篇主要就是介绍一些iOS中常用锁,以及通过一个简单的demo来测试一些锁的性能。
新用户
2018/09/19
1K0
关于多线程中的几把锁
之前lz说后续会继续做SQLite的操作,在lz做版本swift版本操作SQLite过程中遇到了多线程访问的问题,今天就给大家梳理一下其中对共享数据多线程操作中的?,或者是iOS开发中的几种?甚至这些
大话swift
2019/07/04
7820
关于多线程中的几把锁
如何理解互斥锁、条件变量、读写锁以及自旋锁?
锁是一个常见的同步概念,我们都听说过加锁(lock)或者解锁(unlock),当然学术一点的说法是获取(acquire)和释放(release)。
果冻虾仁
2021/12/08
1.8K0
如何理解互斥锁、条件变量、读写锁以及自旋锁?
锁的使用以及底层原理
我们知道,@synchronized是一把互斥锁(互斥锁保证在任何时刻都只能有一个线程访问该对象),它通过大括号来作为加锁、解锁的标识。
拉维
2021/04/16
7150
linux中实现线程同步的6种方法
最后运行的结果不是固定的,有可能是0、-1,如果有这个ticket_num变量代表是库存的话,那么就会出现库存为负数的情况,所以需要引入线程同步来保证线程安全。
全栈程序员站长
2022/09/14
9970
详解Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量
---- Hello、Hello大家好,我是木荣,今天我们继续来聊一聊Linux中多线程编程中的重要知识点,详细谈谈多线程中同步和互斥机制。 同步和互斥 互斥:多线程中互斥是指多个线程访问同一资源时同时只允许一个线程对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的; 同步:多线程同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
Linux兵工厂
2023/02/28
4.1K0
详解Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量
iOS14开发-多线程
不论线程通过如何调度或线程如何交替执行,在不需要做任何干涉的情况下,其执行结果保持一致符合预期,则称之为线程安全。
YungFan
2021/06/08
1.6K0
iOS14开发-多线程
iOS 多线程之线程锁Swift-Demo示例总结
线程锁是什么       在前面的文章中总结过多线程,总结了多线程之后,线程锁也是必须要好好总结的东西,这篇文章构思的时候可能写的东西得许多,只能挤时间一点点的慢慢的总结了,知道了线程之后要了解线程锁就得先了解一下什么是“线程锁”。       “线程锁”一段代码在同一个时间内是只能被一个线程访问,为了避免在同一时间内有多个线程访问同一段代码就有了“锁”的概念,比如说,线程A在访问着一段代码,进入这段代码之后我们加了一个“锁”。这个时候线程B又来访问了,由于有了锁线程B就会等待线程A访问结束之后解开了“锁”
Mr.RisingSun
2018/02/06
3.3K0
iOS 多线程之线程锁Swift-Demo示例总结
12(线程控制)
线程属性主要有: (1)线程的分离状态属性detachstate, (2)线程栈末尾的警戒缓冲区大小guardsize, (3)线程栈的最低地址statckaddr, (4)线程栈的大小stacksize。 如果对现有某个线程的终止状态不感兴趣的话,可以使用pthread_detach函数让操作系统在线程退出时候收回它所占用的资源。
提莫队长
2019/02/21
5890
【iOS底层技术】 锁的基本使用
锁是最常用的同步工具之一。可以使用锁来保护代码的关键部分,该部分代码段一次只能访问一个线程。
CC老师
2021/08/25
1K0
【iOS底层技术】 锁的基本使用
多线程安全-iOS开发注意咯!!!
但是并不是非常完美,因为多线程常常伴有资源抢夺的问题,作为一个高级开发人员并发编程那是必须要的,同时解决线程安全也成了我们必须要要掌握的基础
iOSSir
2019/05/08
9440
Linux下多线程编程详解简介
上面的代码很简单,就是启动一个线程,然后先线程里循环打印字段字符串。我们就以这个最简单的例子来开口。
用户2929716
2018/08/23
4.4K0
linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题
文章主要介绍了在Linux系统中,如何利用自旋锁来实现线程之间的同步和互斥。主要包括了自旋锁的定义、工作原理、使用方式和注意事项,并通过实例介绍了如何在C语言中实现自旋锁。
s1mba
2017/12/28
1.6K0
Linux同步机制(二) - 条件变量,信号量,文件锁,栅栏
1 条件变量 条件变量是一种同步机制,允许线程挂起,直到共享数据上的某些条件得到满足。 1.1 相关函数  #include <pthread.h>  pthread_cond_t cond = PTHREAD_COND_INITIALIZER;  int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t*cond_attr);  int pthread_cond_signal(pthread_cond_t *cond);  int
三丰SanFeng
2018/01/16
3.1K0
Linux线程编程同步之互斥锁和条件变量
今天是最后一篇关于Linux线程编程的文章分享,在这里我们先掌握基础的概念及其应用,后面在慢慢去深入学习。最近看到一句说的非常在理:理论’是你知道是这样,但它却不好用。‘实践’是它很好用,但你不知道是为什么。我想大多数学习者,和我一样,在学习的过程中,都会或多或少的有这种情况,不过自己坚信,你把基础打好(同时学的过程中,不要好高骛远,三心二意的,把自己先暂时用到的东西学明白,再去学其他东西,不要当前的,没学会,又跑去学其他的,而且又学不会,这样浪费时间和精力;这个这里基础打好,举个例子,你的c语言功底要打好,对指针的使用非常熟悉,甚至一些高级用法就是要平时慢慢积累和总结,以及内存原理要知道为什么是这样等方面),后面实战的话,就好多了,至少不会说我这个东西不会那个东西又不会,这样会让自己很痛苦当初为啥没学好基础,现在实战中漏洞百出。好了,废话不多说了,开始下面的主题分享:
用户6280468
2022/03/21
1.8K0
Linux线程编程同步之互斥锁和条件变量
推荐阅读
相关推荐
​iOS线程锁#### 一:十种线程锁
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验