当前位置: 首页 > news >正文

关于atomic 是否是线程安全的问题

在 Objective - C 里,atomic 特性并不能保证对象是完全线程安全的,下面从其基本原理、部分线程安全场景以及局限性来详细说明:

先看一个例子

#import <Foundation/Foundation.h>@interface MyClass : NSObject
@property (atomic, assign) NSInteger count;
@end@implementation MyClass- (void)incrementCount {self.count = self.count + 1;
}@endint main(int argc, const char * argv[]) {@autoreleasepool {MyClass *myObject = [[MyClass alloc] init];dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);// 创建多个线程同时调用 incrementCount 方法for (int i = 0; i < 1000; i++) {dispatch_async(concurrentQueue, ^{[myObject incrementCount];});}// 等待所有任务完成dispatch_barrier_sync(concurrentQueue, ^{NSLog(@"Final count: %ld", (long)myObject.count);});}return 0;
}

多次执行结果

Final count: 996

Final count: 995

Final count: 991

Final count: 1000

Final count: 987

也就是说,结果是不确定,大概率不符合预期(≠1000),那么很显然多线程多操下,atomic并没有保证线程安全

咱们做如下修改,其他代码不变

@property (nonatomic, assign) NSInteger count;

多次执行结果

Final count: 561

Final count: 765

Final count: 567

Final count: 669

Final count: 720

比原来少了,也就是说atomic确实带来了一定的安全效果,只不过不完全保证

atomic 基本原理

atomic 是属性声明时的一个特性,使用 atomic 修饰的属性,在其生成的 settergetter 方法里会加锁,以此来保证同一时间只有一个线程能对该属性进行读写操作。例如下面的代码:

@interface MyClass : NSObject
@property (atomic, strong) NSString *myString;
@end@implementation MyClass
// 编译器自动生成的类似 setter 方法,伪代码示意
- (void)setMyString:(NSString *)myString {@synchronized(self) {_myString = myString;}
}// 编译器自动生成的类似 getter 方法,伪代码示意
- (NSString *)myString {@synchronized(self) {return _myString;}
}
@end

部分线程安全场景

在单纯的属性读写操作中,atomic 能够在一定程度上保证线程安全。比如多个线程同时对 myString 属性进行读写操作,由于 settergetter 方法加了锁,同一时间只会有一个线程执行读写操作,避免了数据竞争的问题。

atomic 的局限性

复合操作不安全atomic 只能保证单个属性的 settergetter 方法是线程安全的,对于复合操作无法保证线程安全。例如下面的代码:

@interface MyClass : NSObject
@property (atomic, assign) NSInteger count;
@end@implementation MyClass- (void)incrementCount {// 这是一个复合操作,先读再写self.count = self.count + 1; 
}@end

incrementCount 方法中,先读取 count 的值,然后加 1 再赋值回去。虽然 count 属性使用了 atomic 修饰,但其 settergetter 方法分别是线程安全的,但整个 incrementCount 操作不是原子的。在多线程环境下,可能会出现多个线程同时读取到相同的 count 值,然后各自加 1 再赋值回去,导致最终的 count 值不符合预期。

 对象的其他操作不安全atomic 仅针对属性的 settergetter 方法加锁,对于对象的其他操作(如调用对象的方法)并不能保证线程安全。例如:

@interface MyClass : NSObject
@property (atomic, strong) NSMutableArray *myArray;
@end@implementation MyClass- (void)addObjectToArray:(id)object {// 这里对 myArray 进行操作,不是 setter 和 getter 方法,atomic 无法保证安全[self.myArray addObject:object]; 
}@end

addObjectToArray 方法中,虽然 myArray 属性使用了 atomic 修饰,但对 myArray 调用 addObject: 方法时并没有加锁,多个线程同时调用该方法可能会导致数据不一致的问题。

综上所述,atomic 只是在属性的基本读写操作上提供了一定的线程安全保障,但不能保证对象在多线程环境下的完全线程安全。如果需要更全面的线程安全,还需要使用其他同步机制(如 @synchronizedNSLock 等)来保护复合操作和对象的其他操作。

atomic vs. 真正的线程安全

atomic@synchronizedGCD 串行队列NSLock
保证 setter/getter 线程安全
保证多个线程同时操作的安全性
推荐用于简单属性多个操作依赖同一数据并发任务处理多线程数据访问
性能较好稍差高效中等
http://www.lryc.cn/news/535466.html

相关文章:

  • 在实体机和wsl2中安装docker、使用GPU
  • HTTP3.0:QUIC协议详解
  • 【EXCEL】【VBA】处理GI Log获得Surf格式的CONTOUR DATA
  • 【数据处理】使用python收集网络数据--爬虫基础
  • 代码随想录二叉树篇(含源码)
  • 网络安全检测思路
  • ios通过xib创建控件
  • 跟着李沐老师学习深度学习(八)
  • 元宵小花灯
  • 算法——搜索算法:原理、类型与实战应用
  • 告别传统测量:三维扫描仪测量工件尺寸
  • win32汇编环境,对话框程序使用跟踪条(滑块)控件示例一
  • WordPress 角标插件:20 种渐变色彩搭配,打造专属菜单标识
  • 【鸿蒙开发】第二十九章 Stage模型-应用上下文Context、进程、线程
  • window 安装GitLab服务器笔记
  • 3dgs 2025 学习笔记
  • 2024.1.2版本Android Studio gradle下载超时问题处理
  • ffmpeg学习:ubuntu下编译Android版ffmpeg-kit
  • mydb:TM实现
  • 神经缩放定律:涌现能力与神经元数量、参数数量、数据集大小以及训练所使用的计算量有关
  • Microsoft Porject常用字段描述
  • web前端开发中vscode常用的快捷键
  • 鲲鹏(ARM64)升级GCC
  • 国产操作系统安装DeepSeek
  • 安科瑞 Acrel-2000ES:解锁储能管理新高度,引领能源未来!
  • DeepSeek总是提示“服务器繁忙,请稍后再试。”的问题的解决办法(替代网站推荐)
  • OpenBayes 教程上新 | 告别服务器繁忙,DeepSeek 一键部署教程上线!
  • 2024年12月中国电子学会青少年软件编程(Python)等级考试试卷(四级)
  • 三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab)
  • 日常知识点之面试后反思裸写string类