LWN: lockless编程模式——relaxed access和partial memory barrier

volatile,指令重排和内存屏障 volatile我们已经再熟悉不过了,他保证了属性的可见性并且禁止指令重排 对于可见性:也就是一个线程改了值,另外一个线程可以立马看到结果,也就是但操作是原子的 对于指令重排,有两种:一种是编译重排,一种是CPU重排(运行期重排),编译重排这里的编译不是变成橙字节码,而是JVM解释成字节码的时候的重排, 那么这两种重排都会有一些保证:编译器重排有一些happenbefore规则,在不违反这些原则的基础上进行重排,而有一些指令他是在编译期间就能知道顺序的,比如说new Object()操作包含以下几步: 阅读详情

关注了就能看到更多这么棒的文章哦~

Lockless patterns: relaxed access and partial memory barriers

February 26, 2021
This article was contributed by Paolo Bonzini
DeepL assisted translation
https://lwn.net/Articles/846700/

本系列中的第一篇文章LWN:介绍lockless算法!对 lockless 算法进行了介绍,以及介绍了"happens before" 关系从而帮助理解 lockless 算法。下一步是看一下 "data race" 的概念,以及为防止 data race 需要使用的 primitives(原语)。我们会继续来了解 relax access、memory barrier,以及如何用它们来实现内核的 seqcount 机制。

对于一些 Linux 内核程序员来说,memory barrier 已经很熟悉了。第一份对内核中数据 concurrent access (并发访问)规范进行初步介绍的文档,其实名字就叫做 memory-barriers.txt。该文档介绍了许多种 memory barrier,以及 Linux 对于 data dependency(数据依赖)和 control dependency(控制依赖)有些什么期望。它还介绍了 "memory-barrier pairing",这可以被看作是 release-acquire 这种配对概念的类似产物,因为它也是用来帮助在跨线程环境中确保 happens before 关系的。

本文将不会像 memory-barriers.txt 中那么详尽地介绍。相反,我们将看看 barrier 比起 acquire and release (获取和释放)模型有些什么差异,以及它们如何简化并确保 seqcount 原语的正确实现。不过,一篇文章哪怕连最常见的 memory barrier 都不可能涵盖完整,所以完整的 memory-barrier 讲解将不得不等待下一期的内容。

Data races, relaxed accesses, and memory barriers

data race 的概念最早是在 C++11 中引入的,此后,它被应用到其他各种语言中,尤其是 C11 和 Rust。这些语言标准在如何处理对数据结构的 lockless access 方面规定得相当严格,它们设计了专门的 atomic load 和 atomic store 原语来实现这个目的。

当两个访问是并发发生的时候(即无法保证它们的 happen before 关系)、其中至少有一个是 store 操作、并且至少有一个没有使用 atomic load 或者 atomic store 原语时,就会发生 data race。每当发生 data race 时,这两个操作的最终结果根据 C11/C++11 定义是不可确定的,这意味着任何结果都有可能。避免了 data race 并不代表说你的算法也是没有 "race condition" 的:data race 是对语言标准(language standard)的违反,而 race condition 则是源于不正确使用锁、不正确的获取/释放语义、或两种错误都存在。

然而,data race 和由此产生的未定义行为(undefined behavior)是很容易避免的。在我们想对一个共享数据进行 store 操作时(这种情形很常见),有两种方法可以做到这一点。第一种是确保这两个操作有 happens before 的顺序关系,也就是使用任意一种可用的获取和释放操作来确保;第二种方法就是使用 atomic load 和 atomic store 操作。

C11、C++11 和 Rust 都提供了各种 memory ordering 机制供程序员在 load 和 store 时使用。我们感兴趣的三种是:acquire(与 load 一起使用)、release(配合 store)和 relaxed(两种操作都适用)。Acquire 和 release 现在应该大家都理解了,Linux 在 smp_load_acquire()和 smp_store_release() 操作中都使用了同样的概念。而 relax 操作则不会对任何跨线程操作保证顺序,也就是不会确保 happen before 的关系。相反,relax 操作只是为了 data race 以及相关的未定义行为,基本上没有用处了。

在实际实现中,Linux 希望编译器和 CPU 在实现的时候都能比语言标准中的定义更加具有可确定性一些。尤其是内核希望普通 load 和 store 都不会因为同时有个 concurrent store 而导致出现 undefined behavior。然而,这种情况下 load 或 store 的最终值仍然是无法确定的,很可能是完全错误的数据。例如可能包括旧的值的一部分和新值的一部分,混合在一起。这意味着,使用从 data race 中 load 出来的指针值的话会出现问题的。

此外,普通的 load 和 store 会受到编译器优化的影响,这可能也会产生意外结果。因此,relaxed-ordering memory operation(放宽内存操作的 ordering 要求)、但同时要保证 atomic 原子操作,这种想法对于 Linux 来说就很有用了。这就是 READ_ONCE()和 WRITE_ONCE() 宏所提供的功能。本系列中的其他文章将会总是显式(explicit)使用 READ_ONCE()和 WRITE_ONCE(),这是如今的 Linux 开发者认为比较好的做法。

这些宏已经出现在上一篇文章的一个例子中了:

它们在使用方式上类似于 smp_load_acquire()和 smp_store_release(),但是它们的第一个参数是赋值的目标(也就是所谓的左值,lvalue),而不是指针。除非有其他机制确保 data race 的结果会被扔掉,否则强烈建议使用 READ_ONCE()和 WRITE_ONCE()来在没有 lock 保护的情况下 load 和 store 公用数据(shared data)。通常情况下,relaxed atomic 操作会与其他一些具有释放和获取语义的原语(或同步机制)一起使用,靠它们来确保 relaxed write 操作和对相同内存位置的 read 操作保证顺序。

举例来说,假设你有多个 work item,它们会用 1 来填充数组中的某些单元,spawn 并完成了这些 work item 之后,必须要先调用 flush_work() ,然后才能对这个数组进行 read 操作。与 pthread_join()类似,flush_work() 也具有获取(acquire)语义,与 work item 的结束是保证同步的(synchronized);flush_work()保证在 work item 完成后才会读取数组内容,并且可以用普通的 load 方式来读取数组了。但是,如果多个、并发的 work item 可以对数组中同一个元素进行 store 操作,就必须使用 WRITE_ONCE(a[x],1),而不是仅仅使用普通的 a[x]=1。

当释放和获取语义是使用 memory barrier 来实现时,就会出现更复杂的情况。为了解释这种情况,我们将讲解 seqcounts 这个实际例子。

Seqcounts

Seqcounts 这种原语是专门用来供消费者(consumer)检测到数据结构在消费者的访问过程中间发生过变化。虽然它们只可以用在特殊情况下(要求被保护的数据量小、在 read 时的 critical p 不会带来副作用、写入速度快并且很少需要写入),但它们有很多有趣的特性,特别是 reader 不会导致 writer 饿死,writer 可以对存放这个 seqcount 的 cacheline 保持所有权。这两个特性使得 seqcounts 在那些需要很强的扩展性(scalability)的场景特别有用。

seqcounts 是一个单生产者、多消费者(single-producer, multiple-consumer)的原语。为了避免有多个并发写入者(concurrent writers),它们通常会与 spinlock 或 mutex 结合使用,形成了我们熟悉的 Linux seqlock_t type。不过,有时在内核之外,你会看到 seqcounts 被称为 seqlocks。

Seqcounts 实际上是一个生成数(generation count),其中如果且仅当 write 操作正在进行时这个生成数才是奇数。如果生成数在 reader 这一边的 critical p 之前的时候看到是奇数,或者在 reader critical p 内部发生了改变,那么说明 reader 就可能已经访问到了一个不一致的状态,必须重新尝试 read 操作。为了使 seqcount 能正确工作,reader 必须要能正确检测到 write 操作的开始和结束。这需要两个 load-acquire 和两个 store-release 操作。假如我们没有已经封装好的 API,通常人们是像下面这样编写 seqcount reader 和 writer 的:

这段代码类似于上一篇文章中所说的 "message passing(消息传递)" 模式。有两对 load-acquire 和 store-release 操作,一组是针对 sc 的,一组是针对 data.x 的,甚至很容易讲清楚为什么需要两对 load-acquire/store-release:

  • 为了让 thread 2 退出循环,那么 sc 的第一次读取操作必须要能看到 thread 1 中第二个 store 操作写进 sc 的偶数值。只要确实看到了,那么 smp_store_release()和 smp_load_acquire()就能保证写入 data 中各个字段的 store 操作是会正常让别人看到的。

  • 如果 thread 2 读取 data.x 的时候,读到了 store 到 data.x 的值,那么 smp_store_release()和 smp_load_acquire() 就确保 thread 2 至少能看到生成数的第一次改变。因此,thread 2 将会继续循环,或者如果它也看到了生出数第二次改变,就会跟上一条所说的一样拿到确保了一致性的新的 data。

然而,这段代码有一个 bug! 因为 writer 在最开头没有进行获取(acquire)操作,所以对 data.y 的写入操作可能会在将奇数值写到 sc 之前完成。(注:文章在 3 月 2 日的更新中指出了这个问题)。对 data 中所有字段使用 load-acquire/store-release 可以避开这个问题,但这样做可能有点过了。而事实上,可以有更好的做法。

上一篇文章中讲过,旧的 Linux 代码可能会使用 smp_wmb(),后面紧跟着 WRITE_ONCE(),而不是 smp_store_release()。同样,有时 READ_ONCE() 后面会跟着使用 smp_rmb(),而不是 smp_load_acquire()。这些 partial barrier 操作会建立起特定的 happens before 这种先后关系。具体来说(但这里的介绍不是很正式),smp_wmb() 会将后续所有的 relaxed store 都变成释放(release)操作,而 smp_rmb() 会将其之前所有的 relaxed load 操作都变成获取(acquire)操作。

我们尝试来将这种用法替换到对 data.x 的访问操作中:

先不谈 barrier 是如何起作用的,至少这里已经可以更加适合用一个易于使用的 API 来包装了。数据完全是通过 relaxed atomic load 和 store 来操作的(尽管在 Linux kernel memory model 中,non-atomic access 也是可以的),barrier 就被隐藏在 seqcount 的 read_seqcount_retry()和 write_seqcount_begin()中了。

上面加入的 barrier 将读和写操作分成了两组,这就保证了 seqcount access 是安全的。然而,有两点需要注意:

  • 首先,barrier 并没有在 relaxed access 之间保证访问顺序。也就是说 thread 2 可能会先看到对 data.y 的改动,然后再看到对 data.x 的改动。这对 seqcount 来说不是问题,因为对 sc 进行检查就可以要求 thread 2 来重新尝试读取,避免它只看到部分 store 结果。

  • 其次,barrier 比 load-acquire 和 store-release 操作要弱一些(weaker)。使用 smp_load_acquire() 进行的读取操作会确保比在其之后所有 load 和 store 都要早完成,同样,smp_store_release() 不仅会确保在它之前的 store 操作之后完成,并且也确保一定会在之前的 load 操作之后完成。相反,smp_rmb() 只保证了 load 操作之间的顺序,而 smp_wmb()只保证了 store 操作之间的顺序。然而,load-store 操作的顺序很少需要保证,这就是为什么 Linux 开发者长期以来只使用 smp_rmb()和 smp_wmb()。

在 seqcounts 这个例子中,load-store 的顺序并没有严格要求,因为 reader 不会在它自己的 critical p 之内对这个共享位置进行写入操作,因此在 writer 对生成数进行更新期间并不会有人在并发地修改这个共享位置。这个推理有点粗糙,但只要代码简单并且完全符合这个模式的话,这个结论其实是准确的。如果 reader 需要对这个共享位置进行 write 操作,那么只要对这些写操作再加上一个其他机制(不能是 seqcount 了)来保护就够了。

前一段的解释虽然不太严谨,但是也说明了了解那些常见的 lockless 编程模式(programming pattern)的重要性。简而言之,这些编程模式能够在不损失精确性的情况下,帮我们用更粗的粒度来思考代码。你可以不用单独去分析每一次内存访问,而是做出 "data.x 和 data.y 受 seqcount sc 保护 "这样的论述,或者对本文中第一个消息传递的例子,可以简单得出"a 是被通过消息传递方式发布给其他线程的"。在某种程度上来说,熟练掌握 lockless 编程模式就意味着能够得出类似这样的结论,并利用这些结论来理解代码。

我们对 memory barrier 的初步探讨到此结束。这个话题自然还有很多内容没有讲完,本系列的下一期将深入探讨完整的 memory barrier,包括它们是如何其效果的、以及它们在内核中是如何使用的。

参考此系列上一篇文章:LWN:介绍lockless算法!

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

CoMP 协同多点传输技术 CoMP CoMP是什么 解决什么问题 有什么缺点 CoMP(Coordinated Multiple Points)协同多点传输,通信术语,LTE-A的重要技术之一。 CoMP传输是指地理位置上分离的多个传输点,协同参与为一个终端的数据(PDSCH)传输或者联合接收一个终端发送的数据(PUSCH),参与协作的多个传输点通常指不同小区的基站。CoMP技术将边缘用户置于几个基站的同频率上,几... 阅读详情

相关推荐

tmux + Claude Code 远程开发指南:从 WSL 配置到断线无忧

远程开发中,SSH 连接中断常导致后台任务丢失,这是困扰开发者的经典难题。tmux 作为终端复用器,通过将进程挂在常驻会话中,使其脱离 SSH 连接独立运行,从根本上解决了断线导致的任务终止问题。Claude Code 等 AI 编程代理需要长时间运行并保持交互上下文,恰好依赖这种会话持久化能力。结合 Windows Subsystem for Linux 提供类 Unix 环境,开发者可在 Windows 上实现稳定的远程开发工作流。本文将完整介绍从 WSL 环境配置、tmux 会话管理,到与 Claud

weixin_30423065的博客 348

一文深入分析-内核并发消杀器(KCSAN)

KCSAN(Kernel Concurrency Sanitizer)是一种动态竞态检测器,它依赖于编译时插装,并使用基于观察点的采样方法来检测竞态,其主要目的是检测数据竞争。KCSAN是一种检测LKMM(Linux内核内存一致性模型)定义的数据竞争(data race)的工具,同时它也可以控制报告哪种类型的数据竞争。KCSAN知道LKMM定义的所有标记原子操作,以及LKMM尚未提到的操作,例如原子位掩码操作(bit mask)。

youzhangjing_的博客 1186

两张 300I Duo 部署 Qwen3.5‑32B

开发者成功使用两张华为300IDuo(共4颗Ascend310P3芯片)部署Qwen3/Qwen3.5的30B/32B模型,并公开详细步骤。关键点包括:硬件需两张300IDuo(每芯片44GB显存),软件需CANN≥24.1和MindIE2.3.0专用镜像。部署流程涵盖驱动安装、模型下载(需修改为FP16格式)、容器启动、张量并行配置(TP=4)等环节。实测显示每芯片显存占用20-35GB,系统稳定运行。该方案已在知乎等平台验证可行,适用于Qwen3.5-32B等同类模型。

evering的博客 2251

重磅消息!!!微软为在Linux程序代码留下“Big Boobs”字句致歉

他在由微软提供的一段二万行的程序代码中,发现了一般文字列“0xB16B00B5”。如果将“i”置换成1“1”、“o”置换成“0”、并以16进位文字表现的Hexspeak写出,“0xB16B00B5”便会变成“big boobs”。“0xB16B00B5”是Linux在Hyper-V的Guest OS状态下,证明其身份的签名档的值,此值原本是“0x0B00B135”。事件流传后NetworkWorld的记者耳中,记者就此向微软查证,45分钟后微软致歉,并表示会尽快提供修正档,至今并未发表任何评论。

u014389734的博客 1万+

当windows安装git时出现以下错误提示

Windows安装Git时出现多个系统配置设置失败错误(exit code 4294967295),提示包括无法设置textconv、LFS过滤器和SSL等配置项。关键问题在于scalar.exe版本不兼容,系统提示"该版本的scalar.exe与你运行的Windows版本不兼容"。解决方案是检查程序版本是否正确,下载与Windows系统兼容的正确版本重新安装即可。

沧澜的博客 1875

用 dism 合并与删除 wim 映像

一、合并 假设 installA.wim 有 3 个映像,installB.wim 有 1 个映像。 1、全部合并 将 installA.wim 中的 3 个卷映像合并到 installB.wim 中,这样 installB.wim 中的卷映像增加到 4 个。 dism/export-image/sourceimagefile:d:\installA.wim/sourceindex:1/destinationimagefile:d:\installB.wim dism/export-image/source

KefanWon的博客 5198

Linux内核中KCSAN 数据竞争检测

共享可写数据,并行执行时需要用锁来保护,或用lock-free。

2551

Spacedesk保姆级教程:用旧平板给Windows电脑当副屏,从安装到避坑一步到位

本文提供Spacedesk保姆级教程,教你如何将旧平板变成Windows电脑的副屏,从软件安装到网络配置、显示优化及声音交互,一步步避开常见陷阱。通过WiFi实现扩展屏功能,支持4K分辨率和60Hz刷新率,让闲置设备焕发新生。

weixin_42524945的博客 1万+

C++11开发中的Atomic原子操作

C++11开发中的Atomic原子操作 Nicol的博客铭 原文  https://taozj.org/2016/09/C-11%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84Atomic%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C/ 主题 C++ 原子操作在多线程开发中经常用到,比如在计数器,序列产生器等地方,这类情况下数据有并发的危...

weixin_34198762的博客 1272

ABAQUS中CDP模型在钢筋混凝土节点低周反复荷载模拟的关键技术解析

本文深入解析了ABAQUS中CDP模型在钢筋混凝土节点低周反复荷载模拟中的关键技术。通过详细介绍CDP模型的核心价值、建模关键技术、滞回曲线优化方法及典型问题排查指南,帮助工程师精准模拟混凝土的拉伸开裂和压缩压碎行为,提升抗震分析效率。文章还提供了实用的工程应用技巧,如快速建模模板和后处理自动化脚本。

weixin_30555125的博客 525

面试问题总结——关于OpenCV(一)

整理了一下网上和我面试中遇到的关于OpenCV相关的问题。 其中因为我的简历中有个项目用到了特征点检测相关的知识,所以整理了SIFT/SURF和FLANN。 有些知识点也不深入,对于写的不对的地方,欢迎指正。 关于OpenCV的内容 1.OpenCV中cv::Mat的深拷贝和浅拷贝问题   深拷贝:分配新内存的同时拷贝数据,当被赋值的容器被修改时,原始容器数据不会改变。   浅拷贝:仅拷贝数据,当被赋值容器修改时,原始容器数据也会做同样改变。 OpenCV的Mat时,有几种赋值方式分别为:   深.

boss-dog 1万+

KVM虚拟化中TLB刷新漏洞详解:从原理到CVE-2019-3016修复指南

本文深入解析KVM虚拟化中的TLB刷新漏洞CVE-2019-3016,详细阐述其原理、影响范围及修复方案。该漏洞源于x86架构下KVM对延迟TLB刷新机制的实现缺陷,可能导致虚拟机内存访问异常或安全风险。文章提供从补丁应用到验证测试的完整修复指南,并给出虚拟化环境配置和开发优化的长期建议。

weixin_29230059的博客 393

【项目实战】Java9的新特性模块化(Module)

Java 9引入了模块化系统,称为"Java Platform Module System"(JPMS)这个系统允许将Java程序分成模块,每个模块都有自己的规范,可以明确地声明它依赖于哪些其他模块,并且只能访问被其所依赖的模块暴露的API。这样可以模块化就是增加了更高级别的聚合,是Package的封装体。Package是一些类路径名字的约定,而模块是一个或多个Package组成的封装体。

奶爸的编程之路,也就一周冷个三天 1896

LWN:以QEMU为例解析软件复杂度!

关注了就能看到更多这么棒的文章哦~A QEMU case study in grappling with software complexityOctober 12, 2021This a...

Linux News搬运工 451

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

学习load acquire 和store release

在学习BOOST多线程库的原码时,顺便看了一下它的互斥量basic_timed_mutex的实现方式。它和WINDOWS自身的CriticalSection很相似,唯一不同的就是basic_timed_mutex有等待时间的功能。http://blogs.msdn.com/b/kangsu/archive/2007/07/16/volatile-acquire-release-memory-fences-and-vc2005.aspxhttp://www.cnblogs.com/lxconan/archiv

程勇新的专栏 7630

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

腾讯云连续第二年登上 KVM 全球开源贡献榜

在近期举行的 KVM Forum 2018 大会上,KVM 主要维护者 Paolo Bonzini 介绍了 KVM 开源项目的当前进展,并统计了 2018 年全球企业对 KVM 的贡献。...

weixin_34050427的博客 189

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深入浅出Linux内核中的内存屏障

工程师的圣地—Linux内核, 谈谈内核的架构 5个方面分析内核架构 linux内核,进程调度器的实现,完全公平调度器 CFS 深透剖析Linux内核字符与块设备驱动程序 抽象内存模型 指令重排 每个 CPU 运行一个程序,程序的执行产生内存访问操作。在这个抽象 CPU 中,内存 操作的顺序是松散的,CPU 假定进程间不依靠内存直接通信,在不改变程序执行 结果 的推测下由自己方便的顺序执行内存访问操作。 例如,考虑下面的执行过程: { A = 1 b = 2} 这有 24 中内存访问操作的组合,每种组合

C/C++Linux、音视频、DPDK 4242

linux内核互斥同步之互斥体

互斥体 在linux内核中,除信号量以外,还有一个类似的实现叫作互斥体Mutex。 信号量的count成员可以初始化为1,并且down和up操作也可以实现类似Mutex的作用,那为什么还可以单独实现Mutex机制,Mutex的语义相对于信号量要简单轻便一些,在锁争用激烈的测试场景下,Mutex比信号量执行速度快,可扩展性更好。 1.互斥体定义 struct mutex { /* 1: unlocked, 0: locked, negative: locked, possible waiters */ a

wll1228的博客 1582

smp_load_acquire smp_store_mb 和 smp_store_release 简介

和是 Linux 内核中用于多核数据同步的关键内存屏障原语。它们通过控制指令和内存访问顺序,确保多核系统中的数据可见性和操作原子性。

六六哥的博客 747

linux READ_ONCE/WRITE_ONCE/ACCESS_ONCE和smp_store_release/smp_load_acquire宏定义实现

READ_ONCE,WRITE_ONCE和 ACCESS_ONCE 宏在linux内核中出现的频率极高。那么这三个宏到底起了什么样的作用呢? smp_store_release/smp_load_acquire又如何呢?

Amelio Ming 1005

Linux内核 -- 多核数据同步原语言之 smp_load_acquire 的作用与使用

用于在读取共享变量时提供获取(acquire)内存屏障,确保在读取该变量后的所有操作只能在其之后执行。这种语义在实现锁、信号量、状态标志等多核间同步机制时非常有用,以确保数据的可见性和操作的顺序性。在 Linux 内核代码中,合理使用和可以避免数据竞争和内存一致性问题,从而确保代码在多核环境中的正确性。

sz66cm 学习随笔 1061

Linux aarch64 中对内存屏障的定义

Linux aarch64 中对内存屏障的定义

suyanqiangqq的博客 779

内存屏障:smp_store_release与smp_load_acquire

在多处理器系统中,CPU为了提高效率会对指令执行顺序进行重排,这可能导致共享数据访问出现意外结果。内存屏障(Memory Barrier)是解决这一问题的关键机制,而`smp_store_release`与`smp_load_acquire`是Linux内核中用于实现释放-获取(Release-Acquire)语义的重要原语。本文将从实际应用场景出发,解析这两个接口的工作原理及使用方法。 ## ...

gitblog_01037的博客 722

Linux checkpatch.pl

Checkpatch(scripts/checkpatch.pl)isaperlscriptwhichchecksfortrivialstyleviolationsinpatchesandoptionallycorrectsthem.Checkpatchcanalsoberunonfilecontextsandwithoutthekerneltree.Checkpatchisnotalwaysright.Yourjudgementtakesprecedenceovercheckpatchmessages。.

3700

学内核之十一:ARM64屏障指令使用指南

介绍arm平台屏障指令

wwwyuewww的专栏 2456

LWN: Lockless编程模式 - 最后的一些话题!

关注了就能看到更多这么棒的文章哦~Lockless patterns: some final topicsMarch 29, 2021This article was contribute...

Linux News搬运工 592
上一篇: LWN: 5.12 合并窗口,第二部分!
下一篇: LWN: Fedora的后备域名解析服务器
LinuxNews搬运工
博客等级 码龄7年 438粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值