volatile与synchronize区别:

本文探讨了volatile与synchronized的区别:volatile作为轻量级线程同步机制,在性能上优于synchronized;volatile确保变量的可见性和一定程度上的有序性,但不保证原子性;synchronized则保证了原子性和可见性,并可能在多线程访问时导致阻塞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

volatile与synchronize区别:

1.volatile是线程同步的轻量级实现,所以volatile的性能要比synchronize好;volatile只能用于修饰变量,synchronize可以用于修饰方法、代码块。随着jdk技术的发展,synchronize在执行效率上会得到较大提升,所以synchronize在项目过程中还是较为常见的;
2.多线程访问volatile不会发生阻塞;而synchronize会发生阻塞;
3.volatile能保证变量在私有内存和主内存间的同步(可见性在一定程度上保证有序性),但不能保证变量的原子性;(lock)synchronize可以保证变量原子性;
4.volatile保证变量在多线程之间的可见性;synchronize是多线程之间访问资源的同步性;所有同步操作都要保证其 原子性与可见性,有序性;

原子性:对一个操作或多个操作一旦执行过程不被任何因素打断,对变量的原子操作,都是原子的不因多线程访问而导致脏数据;AtomicIntegerAtomicIntegerArray是基于Integer类型;AtomicReferenceAtomicReferenceArray基于引用类型;AtomicBoolean等等

                   可见性: CPU资源一直被占用的时候,工作内存与主内存之间未及时同步数据;

                    有序性:对语句进行优化进行指令重排(数据依赖性)但会保证程序最终结果和执行结果相同;

 

<think>好的,我现在要分析用户提供的这个函数`static inline void writew(uint16_t val, volatile void *addr)`,并解释它的作用工作原理。首先,我需要理解每一部分代码的功能。 首先,函数声明是`static inline`,这意味着它是一个内联函数,通常用于头文件中,编译器会尝试将函数体直接插入到调用处,以减少函数调用的开销。返回类型是`void`,参数有两个:一个`uint16_t`类型的值`val`一个指向`volatile void`的指针`addr`。 接下来,函数体内有两个`__sync_synchronize()`调用。我记得`__sync_synchronize()`是GCC提供的内建函数,用于内存屏障(memory barrier),确保在此之前的读写操作都完成之后,才会执行之后的指令。这通常用于多线程或并发环境中,保证内存操作的顺序性。 中间的`asm volatile`部分是内联汇编,这里执行实际的写入操作。汇编指令是`movw %0,%1`,其中`movw`是移动字(16位)数据的指令。这里的占位符`%0``%1`对应后面的输入操作数。根据约束条件,`"r" (val)`表示将`val`放入寄存器,`"m" (*(volatile uint16_t *)addr)`表示将`addr`指向的内存地址作为内存操作数。`volatile`关键字告诉编译器不要优化这段汇编,确保每次执行都实际运行。 用户可能想知道这个函数的作用,特别是在ARM架构下的用途。考虑到之前用户询问过在ARM编译rdma-core,可能他们对底层硬件操作或内核驱动开发感兴趣。这个函数看起来像是用于直接写入内存映射的I/O寄存器,常见于设备驱动中,特别是需要原子操作或严格时序控制的情况。 需要确认`movw`在ARM汇编中的有效性。因为之前的示例可能是在x86架构下的代码,而用户现在可能在ARM环境下工作。如果用户是在ARM架构下使用这个函数,那么`movw`指令是否正确?在ARM中,`movw`用于将16位立即数加载到寄存器,而存储到内存通常使用`str`指令。因此,这段内联汇编可能不适用于ARM,而更适用于x86或其他架构。这可能是一个关键点,需要指出用户提供的代码可能不适用于ARM,或者需要调整汇编指令以适应ARM架构。 此外,`volatile void *addr`转换为`volatile uint16_t *`,是为了确保编译器不会优化掉对内存地址的访问,每次读写都实际执行,这对于内存映射的I/O设备非常重要。 总结,这个函数的作用是以原子方式将16位值写入指定的内存地址,同时使用内存屏障确保操作的顺序性。但需要注意架构差异,特别是在ARM下可能需要不同的汇编指令。</think>### **函数解析:`static inline void writew(uint16_t val, volatile void *addr)`** 此函数用于向指定内存地址**原子写入一个16位值**,通常用于操作硬件寄存器或内存映射I/O(MMIO),需结合多线程/并发场景下的内存同步要求。以下分步解析其实现用途: --- #### **1. 函数声明参数** ```c static inline void writew(uint16_t val, volatile void *addr) ``` - **`static inline`** 声明为静态内联函数,避免函数调用开销,适用于高频调用的底层操作(如硬件寄存器写入)。 - **`volatile void *addr`** `volatile`关键字告知编译器此地址内容可能被硬件或外部事件修改,禁止优化对其的访问(如缓存寄存器读取)。 --- #### **2. 内存屏障:`__sync_synchronize()`** ```c __sync_synchronize(); // 写操作前的屏障 asm volatile(...); __sync_synchronize(); // 写操作后的屏障 ``` - **作用** `__sync_synchronize()`是GCC内置函数,插入**全内存屏障(Full Memory Barrier)**,确保: 1. 屏障前的所有内存操作(读/写)在屏障后可见。 2. 编译器不会重排屏障前后的指令。 - **为何需要两次屏障?** - 第一个屏障:确保写入前的其他内存操作(如数据准备)已完成。 - 第二个屏障:确保写入操作完成后,后续指令不会乱序执行。 --- #### **3. 内联汇编:原子写入16位值** ```c asm volatile( "movw %0,%1" // 将val的值写入addr指向的内存 : // 无输出操作数 :"r" (val), "m" (*(volatile uint16_t *)addr) // 输入约束 ); ``` - **`asm volatile`** - `volatile`禁止编译器优化此段汇编(确保每次调用均执行)。 - **汇编指令:`movw`** - `movw`在x86架构中表示“移动字(16位)数据”,但在**ARM架构下需替换为`strh`指令**(如`strh %0, [%1]`)。 - **注意**:此代码段是x86语法,若需在ARM平台运行,需修改汇编指令。 - **操作数约束** - `"r" (val)`:将`val`的值存入通用寄存器。 - `"m" (*(volatile uint16_t *)addr)`:将`addr`强制转换为`volatile uint16_t*`类型,表示操作对象是16位内存地址。 --- #### **4. 典型应用场景** 1. **硬件寄存器操作** 写入网卡、DMA控制器等硬件设备的控制寄存器。例如: ```c // 向地址0xFE200000写入配置值0x1A2B writew(0x1A2B, (void*)0xFE200000); ``` 2. **多核/多线程同步** 结合内存屏障,确保共享内存的修改对其他CPU核心可见。 --- #### **5. ARM架构适配问题** - **指令替换** ARM使用`strh`(Store Register Halfword)实现16位写入,需调整汇编部分: ```c asm volatile("strh %0, [%1]" : : "r" (val), "r" (addr)); ``` - **内存屏障** ARM需使用`dmb`指令或`__dmb()`内置函数替代`__sync_synchronize()`: ```c __dmb(0xF); // 全系统内存屏障(ARMv7/v8) ``` --- ### **示例对比:x86ARM实现** | 架构 | 写入指令 | 内存屏障 | |------|---------------|------------------------| | x86 | `movw %0, %1` | `__sync_synchronize()` | | ARM | `strh %0, [%1]` | `__dmb(0xF)` | --- ### **注意事项** 1. **平台兼容性** 示例代码为x86语法,**直接用于ARM会导致编译错误**,需按上述方法修改。 2. **原子性保证** `movw`或`strh`本身是否为原子操作取决于硬件实现。在ARM中,未对齐的16位写入可能被拆分为多个总线操作,需结合地址对齐性判断。 3. **性能影响** 频繁使用内存屏障会降低性能,需根据场景权衡(如是否真需严格顺序)。 --- ### **扩展:为何需要此类底层操作?** 在操作系统内核或嵌入式开发中,直接操作硬件寄存器是常见需求。例如: - 启用设备的中断配置。 - 设置DMA传输的目标地址。 - 调试时手动触发硬件信号。 此类代码通常出现在设备驱动或裸机程序中,需确保时序原子性,避免硬件状态混乱。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值