使用 GCD 实现属性的多读单写

在这里插入图片描述

使用 Grand Central Dispatch (GCD) 实现多读单写的属性

  1. 首先需要确保在多线程环境下的线程安全性。
  2. 可以使用 GCD 提供的读写锁机制 dispatch_rwlock_t 或者 dispatch_queue_t 来实现这个功能。

Swift版本的实现

  1. 怎样创建一个并发队列 ?
    // 使用 Swift 来实现的首个好处就是:避免使用低等级的 C 语言 API (真的很难用🤣)
    let queue = DispatchQueue(label: "io.sqi.queue.concurrent", attributes: .concurrent)
    
  2. Swift 的属性怎样重写 setter 和 getter ?(是不是 Objective-C 喝多了😂, 应该像下面 3 这样问)
  3. 应该使用什么类型的属性,setter 和 getter 怎样实现 ?

    使用计算属性,setter 使用 set { }, 注意不是 didSet { }, getter 使用 get { }

import Foundationclass SQIObject<T> {private var _threadSafeProperty: Tprivate let queue = DispatchQueue(label: "io.sqi.threadSafeProperty", attributes: .concurrent)init(threadSafeProperty: T) {self._threadSafeProperty = threadSafeProperty}var threadSafeProperty: T {get {return queue.sync {return _threadSafeProperty}}set {queue.async(flags: .barrier) {// 如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValueself._threadSafeProperty = newValue}}}
}// 示例使用
let demo = SQIObject(threadSafeProperty: 0)// 多读示例
DispatchQueue.concurrentPerform(iterations: 10) { index inprint("Read \(index): \(demo.threadSafeProperty)")
}// 单写示例
DispatchQueue.global().async {demo.threadSafeProperty = 42print("ThreadSafeProperty updated to 42")
}// 确保程序不会立即退出
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {print("Final threadSafeProperty: \(demo.threadSafeProperty)")
}
RunLoop.main.run(until: Date(timeIntervalSinceNow: 2))

在这个示例中:

  1. SQIObject 类封装了一个泛型属性,并使用 GCD 的并发队列来确保线程安全。
  2. 读取操作使用 queue.sync 同步读取,以确保多个读取操作可以同时进行。
  3. 写入操作使用 queue.async(flags: .barrier),这确保了在写入操作执行时,所有的读取操作都会被阻塞,直到写入操作完成。这就实现了多读单写的属性。

Objective-C 版本的实现

利用 Grand Central Dispatch (GCD) 中的并发队列和屏障块来确保线程安全。

#import <Foundation/Foundation.h>@interface SQIObject : NSObject
// 一个线程安全的多读单写属性
@property (nonatomic, strong) id threadSafeProperty;- (instancetype)initWithThreadSafeProperty:(id)threadSafeProperty;@end@implementation SQIObject {id _threadSafeProperty;dispatch_queue_t _queue;
}- (instancetype)initWithThreadSafeProperty:(id)threadSafeProperty {self = [super init];if (self) {_threadSafeProperty = threadSafeProperty;_queue = dispatch_queue_create("io.sqi.queue.concurrent", DISPATCH_QUEUE_CONCURRENT);}return self;
}- (id)threadSafeProperty {__block id result;dispatch_sync(_queue, ^{result = _threadSafeProperty;});return result;
}- (void)setThreadSafeProperty:(id)threadSafeProperty {dispatch_barrier_async(_queue, ^{_threadSafeProperty = threadSafeProperty;});
}@endint main(int argc, const char * argv[]) {@autoreleasepool {SQIObject *object = [[SQIObject alloc] initWithThreadSafeProperty:@0];// 多读示例dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {NSLog(@"Read %zu: %@", index, [object threadSafeProperty]);});// 单写示例dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[SQIObject setThreadSafeProperty:@42];NSLog(@"ThreadSafeProperty updated to 42");});// 确保程序不会立即退出dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@"Final threadSafeProperty: %@", [object threadSafeProperty]);CFRunLoopStop(CFRunLoopGetMain());});CFRunLoopRun();}return 0;
}

在这个示例中:

  1. SQIObject 类封装了一个属性 threadSafeProperty,并使用 GCD 的并发队列 _queue 来确保线程安全。
  2. 读取操作使用 dispatch_sync 同步读取,以确保多个读取操作可以同时进行。
  3. 写入操作使用 dispatch_barrier_async,这确保了在写入操作执行时,所有的读取操作都会被阻塞,直到写入操作完成。这就实现了多读单写的属性。

细节分析

getter 方法为什么这样实现 ?感觉有点怪

- (id)threadSafeProperty {__block id result;dispatch_sync(_queue, ^{result = _threadSafeProperty;});return result;
}
  1. 首先,想要将读取操作放入队列,必须要有如下片段:

    - (id)threadSafeProperty {dispatch_(a)sync(_queue, ^{// 读取操作});
    }
  2. 不能在 block 内部直接 return, 会报类型不匹配

    // Incompatible block pointer types passing 'id (^)(void)' to parameter of type 'dispatch_block_t _Nonnull' (aka 'void (^)(void)')
    - (id)threadSafeProperty {dispatch_(a)sync(_queue, ^{return _threadSafeProperty;});
    }
    
  3. 所以只能先声明临时变量,然后在 block 中执行 assignment (赋值),完成后,return 出去,结果就是:

    - (id)threadSafeProperty {__block id result;dispatch_(a)sync(_queue, ^{result = _threadSafeProperty;});return result;
    }
  4. 而如果想要获取有效的 return 值,GCD Block 中的操作必须 block 线程,在 return 之前完成 assignment, 故只能选择 dispatch_sync,所以最终的结果是:

    - (id)threadSafeProperty {__block id result;dispatch_sync(_queue, ^{result = _threadSafeProperty;});return result;
    }

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/30458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.net 奇葩问题调试经历之1——在红外相机获取温度时异常

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔序言 我们在研发中,经常除了造产品…

吉时利Keithley2602B数字源表

吉时利Keithley2602B数字源表 2601B、2602B、2604B 系统 Sourcemeter SMU 仪器 2601B、2602B 和 2604B 系统 Sourcemeter SMU 仪器为 40W DC / 200W 脉冲 SMU&#xff0c;支持 10A 脉冲&#xff0c;3A 至 100fA 和 40V 至 100nV DC。它们将精密电源、实际电流源、6 位数字万用…

使用asyncua模块的call_method方法调用OPC UA的Server端方法报错:asyncio.exceptions.TimeoutError

使用asyncua模块的call_method方法调用OPC UA的Server端方法报错&#xff1a;asyncio.exceptions.TimeoutError 报错信息如下&#xff1a; Traceback (most recent call last): asyncio.run(main()) File “D:\miniconda3\envs\py31013\lib\asyncio\runners.py”, line 44, in…

反激开关电源整流桥选型及计算

整流桥的作用就是把输入交流电压整形成直流电压&#xff0c;把正弦波整成馒头波&#xff0c;由于整流管的单向导电 性&#xff0c;在输入电压瞬时值小于滤波电容上电压时整流桥&#xff0c;在这个时候是不导通的&#xff0c;使整流桥的电流变 成2-3ms左右的窄脉冲。为获得所需…

【数据结构】选择题

在数据结构中&#xff0c;从逻辑上可以把数据结构分为&#xff08;线性结构和非线性结构&#xff09; 当输入规模为n时&#xff0c;下列算法渐进复杂性中最低的是&#xff08;&#xff09; 时间复杂度 某线性表采用顺序存储结构&#xff0c;每个元素占4个存储单元&#xf…

13.3 Go 性能优化

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【MAVEN学习 | 第1篇】Maven介绍与安装

文章目录 前言 一. Maven主要作用1.1 依赖管理1.2 项目构建 二. Maven安装和配置2.1 安装2.2 配置环境变量2.3 命令测试2.4 配置文件&#xff08;1&#xff09;依赖本地缓存位置&#xff08;本地仓库位置&#xff09;&#xff08;2&#xff09;配置国内阿里镜像&#xff08;3&a…

WPS相同字体但是部分文字样式不一样解决办法

如下图&#xff0c;在使用wps编辑文档的时候发现有些电脑的文字字体很奇怪&#xff0c;但是把鼠标移到这个文字的位置&#xff0c;发现它和其他正常文字的字体是一样的&#xff0c;都是仿宋_GB2312 正常电脑的文字如下图所示 打开C:\Windows找到Fonts这个文件夹 把仿宋_GB2312这…

【启明智显产品介绍】工业级HMI芯片Model3芯片详解(二)图像显示

Model3芯片是一款集大容量存储、宽温操作范围及多功能接口于一身的MCU&#xff0c;配备了 2D 图像加速引擎和 PNG 解码/JPEG 编解码引擎&#xff0c;可以满足各类交互设计场景和多媒体互动需求&#xff0c;具有高可靠性、高安全性、高开放度的特点&#xff0c;可以面向于泛工业…

Stable Diffusion 3 大模型文生图实践

windows教程2024年最新Stable Diffusion本地化部署详细攻略&#xff0c;手把手教程&#xff08;建议收藏!!)_stable diffusion 本地部署-CSDN博客 linux本地安装教程 1.前期准备工作 1&#xff09;创建conda环境 conda create --name stable3 python3.10 2&#xff09;下…

【UBEMX安装和使用】

UBEMX安装 1. UBEMX介绍2. 官网下载软件3. 安装步骤下载和关联的STM32Cube固件包 1. UBEMX介绍 STM32CubeMX是一种图形工具&#xff0c;通过分步过程可以非常轻松地配置STM32微控制器和微处理器&#xff0c;以及为Arm Cortex-M内核或面向Arm Cortex-A内核的特定Linux设备树生成…

Flutter调用本地web

前言: 在目前Flutter 环境中&#xff0c;使用在线 webview 是一种很常见的行为 而在 app 环境中&#xff0c;离线使用则更有必要 1.环境准备 将依赖导入 2.引入前端代码 前端代码有两种情况 一种是使用打包工具 build 而来的前端代码 另一种情况是直接使用 HTML 文件 …

YoloV8改进策略:Block篇|即插即用|StarNet,重写星操作,使用Block改进YoloV8(全网首发)

摘要 本文主要集中在介绍和分析一种新兴的学习范式——星操作&#xff08;Star Operation&#xff09;&#xff0c;这是一种通过元素级乘法融合不同子空间特征的方法&#xff0c;通过元素级乘法&#xff08;类似于“星”形符号的乘法操作&#xff09;将不同子空间的特征进行融…

java:动态代理和cglib代理的简单例子

# 项目代码资源&#xff1a; 可能还在审核中&#xff0c;请等待。。。 https://download.csdn.net/download/chenhz2284/89457803 # 项目代码 【pom.xml】 <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version&…

WGCLOUD的web ssh提示websocket服务连接已断开

这个问题一般是server主机没有开放端口9998&#xff0c;因为9998是web ssh的端口&#xff0c;需要开放 我们只要在防火墙&#xff0c;或者安全软件&#xff0c;把这个端口开放了就可以了

小白学-WEBGL

第一天&#xff1a; 1.canvas和webgl的区别 Canvas 和 WebGL 都是用于在网页上绘制图形的技术&#xff0c;它们通过浏览器提供的 API 使开发者能够创建丰富的视觉内容&#xff0c;但它们的工作原理和用途有所不同。 Canvas Canvas API 提供了一个通过 JavaScript 和 HTML <…

Xtuner微调

环境安装 studio-conda xtuner0.1.17 conda activate xtuner0.1.17 进入家目录 &#xff08;~的意思是 “当前用户的home路径”&#xff09; cd ~ 创建版本文件夹并进入&#xff0c;以跟随本教程 mkdir -p /root/xtuner0117 && cd /root/xtuner0117 拉取 0.1.17 的版…

Java IO模型BIO、NIO、AIO介绍

第一章 BIO、NIO、AIO课程介绍 1.1 课程说明 在java的软件设计开发中&#xff0c;通信架构是不可避免的&#xff0c;我们在进行不同系统或者不同进程之间的数据交互&#xff0c;或者在高并发下的通信场景下都需要用到网络通信相关的技术&#xff0c;对于一些经验丰富的程序员来…

Windows桌面运维----第四天

1、U盘故障打不开&#xff1a; 操作方式&#xff1a;WinR打开运行&#xff0c;输入cmd确定&#xff0c;在&#xff08;C:\Users\Administrator>&#xff09;后输入chkdsk,空格&#xff0c;输入U盘盘符&#xff0c;例如F:/F&#xff0c;回车&#xff0c;等待修复完成。 2、…

自然语言处理概述

目录 1.概述 2.背景 3.作用 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 5.1.十个应用场景 5.2.文本分类 5.2.1.一般流程 5.2.2.示例 6.使用示例 7.总结 1.概述 自然语言处理&#xff08;NLP&#xff09;是计算机科学、人工智能和语言学的交叉领域&#xff0c;旨在实…