iOS - 原子操作

news2025/1/10 9:58:44

在 Objective-C 运行时中,原子操作主要通过以下几种方式实现:

1. 基本原子操作

// 原子操作的基本实现
#if __has_feature(c_atomic)

#define OSAtomicIncrement32(p)        __c11_atomic_add((_Atomic(int32_t) *)(p), 1, __ATOMIC_RELAXED)
#define OSAtomicDecrement32(p)        __c11_atomic_sub((_Atomic(int32_t) *)(p), 1, __ATOMIC_RELAXED)
#define OSAtomicIncrement32Barrier(p) __c11_atomic_add((_Atomic(int32_t) *)(p), 1, __ATOMIC_SEQ_CST)
#define OSAtomicDecrement32Barrier(p) __c11_atomic_sub((_Atomic(int32_t) *)(p), 1, __ATOMIC_SEQ_CST)

#else

// 使用内联汇编实现原子操作
static ALWAYS_INLINE int32_t 
OSAtomicIncrement32(volatile int32_t *value) {
    return __sync_fetch_and_add(value, 1) + 1;
}

static ALWAYS_INLINE int32_t 
OSAtomicDecrement32(volatile int32_t *value) {
    return __sync_fetch_and_sub(value, 1) - 1;
}

#endif

2. 自旋锁实现

typedef struct {
    volatile int32_t value;
} OSSpinLock;

// 自旋锁的原子操作
static ALWAYS_INLINE void
OSSpinLockLock(volatile OSSpinLock *lock)
{
    do {
        while (lock->value != 0) {
            // 忙等待
            __asm__ volatile ("pause");
        }
    } while (!OSAtomicCompareAndSwap32(0, 1, &lock->value));
}

static ALWAYS_INLINE bool
OSSpinLockTry(volatile OSSpinLock *lock)
{
    return OSAtomicCompareAndSwap32(0, 1, &lock->value);
}

static ALWAYS_INLINE void
OSSpinLockUnlock(volatile OSSpinLock *lock)
{
    OSAtomicAnd32Barrier(0, &lock->value);
}

3. 比较和交换操作

// 原子比较和交换操作
static ALWAYS_INLINE bool
OSAtomicCompareAndSwapPtr(void *oldp, void *newp, void *volatile *dst)
{
    return __sync_bool_compare_and_swap(dst, oldp, newp);
}

static ALWAYS_INLINE bool
OSAtomicCompareAndSwapLong(long oldl, long newl, volatile long *dst)
{
    return __sync_bool_compare_and_swap(dst, oldl, newl);
}

static ALWAYS_INLINE bool
OSAtomicCompareAndSwap32(int32_t old, int32_t new, volatile int32_t *dst)
{
    return __sync_bool_compare_and_swap(dst, old, new);
}

4. 内存屏障

// 内存屏障实现
#define OSMemoryBarrier()  __sync_synchronize()

static ALWAYS_INLINE void
OSMemoryBarrierBeforeUnlock()
{
#if defined(__arm__) || defined(__arm64__)
    OSMemoryBarrier();
#endif
}

5. 原子引用计数操作

inline bool 
objc_object::rootTryRetain()
{
    return sidetable_tryRetain() || rootRetain_overflow(true);
}

inline bool 
objc_object::sidetable_tryRetain()
{
    SideTable& table = SideTables()[this];
    
    bool result = false;
    
    table.lock();
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it != table.refcnts.end()) {
        RefcountMap::value_type &pair = *it;
        if (pair.second & SIDE_TABLE_RC_PINNED) {
            pair.second += SIDE_TABLE_RC_ONE;
            result = true;
        }
        else if (pair.second & SIDE_TABLE_RC_WEAKLY_REFERENCED) {
            pair.second = SIDE_TABLE_RC_ONE | SIDE_TABLE_RC_WEAKLY_REFERENCED;
            result = true;
        }
    }
    table.unlock();
    
    return result;
}

6. 原子属性访问器

// 原子属性的 getter
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    if (!atomic) return *((id *)((char *)self + offset));
    
    // 原子操作
    spinlock_t& slotlock = PropertyLocks[GOODHASH(offset)];
    slotlock.lock();
    id value = *((id *)((char *)self + offset));
    slotlock.unlock();
    return value;
}

// 原子属性的 setter
static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
                                   ptrdiff_t offset, bool atomic, bool copy) 
{
    if (!atomic) {
        *((id *)((char *)self + offset)) = newValue;
        return;
    }
    
    spinlock_t& slotlock = PropertyLocks[GOODHASH(offset)];
    slotlock.lock();
    *((id *)((char *)self + offset)) = newValue;
    slotlock.unlock();
}

7. 原子操作的使用场景

1. 引用计数管理

// 原子递增引用计数
id objc_retain(id obj) {
    if (!obj) return obj;
    if (obj->isTaggedPointer()) return obj;
    return obj->retain();
}

2. 属性访问

// 原子属性的实现
@property (atomic) NSString *name;

3. 数据结构操作

// 线程安全的数组操作
- (void)addObject:(id)object {
    @synchronized(self) {
        [_array addObject:object];
    }
}

这些原子操作的实现保证了:

  • 原子性:操作要么完全执行,要么完全不执行
  • 可见性:一个线程的修改对其他线程立即可见
  • 有序性:防止指令重排导致的问题

通过这些机制,Objective-C 运行时能够保证多线程环境下的数据一致性和线程安全。

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

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

相关文章

江科大STM32入门——UART通信笔记总结

wx:嵌入式工程师成长日记 1、简介 简单双向串口通信有两根通信线(发送端TX和接收端RX)TX与RX要交叉连接当只需单向的数据传输时,可以只接一根通信线当电平标准不一致时,需要加电平转换芯片 传输模式:全双工;时钟&…

分布式主键ID生成方式-snowflake雪花算法

这里写自定义目录标题 一、业务场景二、技术选型1、UUID方案2、Leaf方案-美团(基于数据库自增id)3、Snowflake雪花算法方案 总结 一、业务场景 大量的业务数据需要保存到数据库中,原来的单库单表的方式扛不住大数据量、高并发,需…

创建基本的 Electron 应用项目的详细步骤

创建一个基本的 Electron 应用项目的详细步骤。我们将从安装 Node.js 开始,然后创建项目文件夹并初始化 Electron 项目。 1. 安装 Node.js 首先,确保你已经安装了 Node.js 和 npm。你可以在终端中运行以下命令来检查是否已经安装: node -v…

对话新晋 Apache SeaTunnel Committer:张圣航的开源之路与技术洞察

近日,张圣航被推选为 Apache SeaTunnel 的 Committer成员。带着对技术的热情和社区的责任,他将如何跟随 Apache SeaTunnel 社区迈向新的高度?让我们一起来聆听他的故事。 自我介绍 请您简单介绍一下自己,包括职业背景、当前的工作…

超完整Docker学习记录,Docker常用命令详解

前言 关于国内拉取不到docker镜像的问题,可以利用Github Action将需要的镜像转存到阿里云私有仓库,然后再通过阿里云私有仓库去拉取就可以了。 参考项目地址:使用Github Action将国外的Docker镜像转存到阿里云私有仓库 一、Docker简介 Do…

JVM实战—OOM的定位和解决

1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是:建立一套监控平台,比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台,就可以接入系统异常的监控和报警,可以设置当系统出现OOM异常&…

你知道智能家居与fpc有哪些关联吗?【新立电子】

智能家居,作为现代科技与家居生活深度融合的产物,它不仅仅是一种技术革新,更是一种生活理念的升级,将家居环境打造成为一个更加智能、舒适和安全的生活空间。 智能家居的核心在于其通过互联网、物联网、人工智能等技术手段&#…

STM32 : PWM 基本结构

这张图展示了PWM(脉冲宽度调制)的基本结构和工作流程。PWM是一种用于控制功率转换器输出电压的技术,通过调整信号的占空比来实现对负载的精确控制。以下是详细讲解: PWM 基本结构 1. 时基单元 ARR (Auto-reload register): 自动…

STM32之一种双通路CAN总线消息备份冗余处理方法(十三)

STM32F407 系列文章 - Dual-CANBus-ProMethod(十三) 目录 前言 一、现状分析 二、解决思路 1.应用场景网络结构图 2.数据发送流程 3.数据接收流程 4.用到的模块 1.CAN网络速率及时间片分配 2.CAN网络消息ID组成 3.设备节点定义 4.数据格式说明…

内网穿透的应用-Ubuntu本地Docker部署Leantime项目管理工具随时随地在线管理项目

文章目录 前言1.关于Leantime2.本地部署Leantime3.Leantime简单实用4.安装内网穿透5.配置Leantime公网地址6. 配置固定公网地址 前言 本文主要介绍如何在本地Linux系统使用Docker部署Leantime,并结合cpolar内网穿透工具轻松实现随时随地查看浏览器页面,…

VulnHub-Acid(1/100)

参考链接: ​​​​​​​【VulnHub】Acid靶场复盘-CSDN博客 靶场渗透(二)——Acid渗透_ambassador 靶场渗透-CSDN博客 网络安全从0到0.5之Acid靶机实战渗透测试 | CN-SEC 中文网 Vulnhub靶场渗透练习(四) Acid - 紅人 - 博客园 红日团队…

HTML5实现好看的端午节网页源码

HTML5实现好看的端午节网页源码 前言一、设计来源1.1 网站首页界面1.2 登录注册界面1.3 端午节由来界面1.4 端午节习俗界面1.5 端午节文化界面1.6 端午节美食界面1.7 端午节故事界面1.8 端午节民谣界面1.9 联系我们界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 H…

git merge与rebase区别以及实际应用

在 Git 中,merge 和 rebase 是两种将分支的更改合并到一起的常用方法。虽然它们都可以实现类似的目标,但它们的工作方式和效果有所不同。 1. Git Merge 定义:git merge 是将两个分支的历史合并在一起的一种操作。当你执行 git merge 时&…

Matlab APP Designer

我想给聚类的代码加一个图形化界面,需要输入一些数据和一些参数并输出聚类后的图像和一些评价指标的值。 gpt说 可以用 app designer 界面元素设计 在 设计视图 中直接拖动即可 如图1,我拖进去一个 按钮 ,图2 红色部分 出现一行 Button 图…

PyCharm 引用其他路径下的文件报错 ModuleNotFound 或报红

PyCharm 中引用其他路径下的文件提示 ModuleNotFound,将被引用目录添加到系统路径: # # 获取当前目录 dir_path os.path.dirname(os.path.realpath(__file__)) # # 获取上级目录 parent_dir_path os.path.abspath(os.path.join(dir_path, os.pardir))…

【HarmonyOS NEXT】鸿蒙应用点9图的处理(draw9patch)

【HarmonyOS NEXT】鸿蒙应用点9图的处理(draw9patch) 一、前言: 首先在鸿蒙中是不支持安卓 .9图的图片直接使用。只有类似拉伸的处理方案,鸿蒙提供的Image组件有与点九图相同功能的API设置。 可以通过设置resizable属性来设置R…

SOLID原则学习,开闭原则

文章目录 1. 定义2. 开闭原则的详细解释3. 实现开闭原则的方法4. 总结 1. 定义 开闭原则(Open-Closed Principle,OCP)是面向对象设计中的五大原则(SOLID)之一,由Bertrand Meyer提出。开闭原则的核心思想是…

【Vue3中使用crypto-js】crypto-js加密解密用法

目录 1、安装crypto2、创建crypto.js文件3、在main.js主文件中进行引用4、页面中进行使用5、实现效果展示6、加密模式解析以及iv参数使用 1、安装crypto npm install crypto-js 如果是在Typescript版本需要再安装 npm install --save types/crypto-js2、创建crypto.js文件 注…

跨界融合:人工智能与区块链如何重新定义数据安全?

引言:数据安全的挑战与现状 在信息化驱动的数字化时代,数据已成为企业和个人最重要的资产之一。然而,随着网络技术的逐步优化和数据量的爆发式增长,数据安全问题也愈变突出。 数据安全现状:– 数据泄露驱动相关事件驱…

简单易用的PDF工具箱

软件介绍 PDF24 Creator是一款简单易用的PDF工具箱,而且完全免费,没有任何功能限制。既可以访问官网在线使用各种PDF工具,也可以下载软件离线使用各种PDF工具。 软件功能 1、PDF转换 支持将多种文件格式(Word、PowerPoint、Exc…