博客
关于我
Linux内核同步机制之(一):原子操作
阅读量:142 次
发布时间:2019-02-26

本文共 1019 字,大约阅读时间需要 3 分钟。

多核系统中,读取-修改-写入操作序列的原子性问题

在多核系统中,读取-修改-写入操作序列面临着严峻的挑战。在多个CPU同时执行同一操作时,可能出现数据覆盖问题。这种情况不仅限于多核系统,还可能在单核系统中由于多线程控制路径交错引发。

1. 读取-修改-写入操作的常见问题

在多核系统中,两个或多个CPU同时读取同一内存变量的值。此时,读取操作可能返回旧值。随后,修改操作由其中一个CPU执行。写入操作时,由于总线arbiter的限制,可能存在先写入再覆盖的情况,导致最终结果错误。

在单核系统中,同样存在内核控制路径交错的问题。例如,在系统调用的中断处理中,中断handler的写入操作可能被系统调用控制路径的写入操作覆盖。

2. 解决方案:原子操作

针对这种情况,内核提供了atomic_t类型。该类型定义了若干原子接口API函数,确保操作的原子性。

3. ARM架构中的实现

在ARM架构中,原子操作分为两类:支持SMP的ARMv6及以后的版本,以及仅支持单核的ARMv6之前的版本。对于支持SMP的版本,原子操作通过特殊的指令完成。对于UP,原子操作则通过关闭中断实现。

4. 汇编实现细节

以atomic_add为例,展示具体实现:

asm volatile (    : "%0 += %1"     : "r"    : "ir"    : "cc");

上述代码中,__volatile__用于防止优化。asm语句定义了一个嵌入式汇编接口,: "%0 += %1"表示将结果保存到输出操作数,"r"表示输出操作数为一个可写寄存器,"ir"表示输入操作数为一个早期覆盖寄存器。"cc"通知GCC汇编器条件码寄存器的变化。

5. 指令细节:LDREX和STREX

LDREX和STREX指令用于实现原子操作。LDREX从内存读取数据至寄存器,并放出两个监控dog。STREX用于写入内存,并根据结果返回状态。LDREX和STREX适用于非共享内存;对于共享内存,需要额外的机制确保互斥。

6. 实现中的关键注意事项

  • 寄存器分配output operand listinput operand list需明确区分,确保编译器正确分配寄存器。
  • 缓存预加载:在使用STREX前,需预加载相关内存至缓存以提高性能。
  • 异常处理:需检查写入结果,若失败则重复操作。
  • 通过以上方法,可以确保读取-修改-写入操作的原子性,从而避免数据错误。

    转载地址:http://rypk.baihongyu.com/

    你可能感兴趣的文章
    php操作mysql用select_php如何操作mysql获取select 结果
    查看>>
    PHP操作符与控制结构
    查看>>
    PHP支付宝SDK使用,电脑网页支付
    查看>>
    php支付宝手机网页支付类实例
    查看>>
    php教程之php空白页的原因及解决方法
    查看>>
    PHP数据库操作
    查看>>
    PHP数据文件过大,导致PHP加速器eaccelerator在PHP5.2版本下崩溃
    查看>>
    RabbitMQ - 死信、TTL原理、延迟队列安装和配置
    查看>>
    PHP数据访问的多重查询(租房子查询)
    查看>>
    RabbitMQ - 如保证消息的可靠性?(消息确认、消息持久化、失败重试机制)
    查看>>
    RabbitMQ - 基于 SpringAMQP 带你实现五种消息队列模型
    查看>>
    php数组函数分析--array_column
    查看>>
    php数组去重复数据的小例子
    查看>>
    php数组实现:哈希 +双向链表
    查看>>
    PHP数组排序函数array_multisort()函数详解(二)
    查看>>
    php数组的几个函数和超全局变量
    查看>>
    PHP文件上传详解
    查看>>
    PHP文件锁
    查看>>
    php文本框输入制定文本,php – 当用户没有向文本框输入任何内容时...
    查看>>
    PHP时间戳和日期相互转换操作总结
    查看>>