Linux __sync_synchronize

2024-03-06 23:18
文章标签 linux sync synchronize

本文主要是介绍Linux __sync_synchronize,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

当我们在做多线程编程的时候,会涉及到一个称为memory order的问题。

例如

int x(0),y(0);
x=4;
y=3;

请问,实际执行的时候,这两条赋值语句谁先执行,谁后执行? 会不会有某个时间点,在某个CPU看来,y比x大?

答案很复杂。本文的目的是从非常实践的角度来考虑这个问题。

首先,它分为两个层面。在编译器看来,x和y是两个没有关联的变量,那么编译器有权利调整这两行代码的执行顺序,只要它乐意。

其次,CPU也有权利这么做。

如果我非要严格要求顺序,那么就应该插入一个memory barrier

int x(0),y(0);
x=4;
在此插入memory barrier指令
y=3;

下面要论述,中间那行怎么写。请耐心看下去,因为大多数人都在瞎整。

gcc的手册中有一节叫做”Built-in functions for atomic memory access”,然后里面列举了这样一个函数:

__sync_synchronize (…)

This builtin issues a full memory barrier.

来,我们写段代码试下:

int main(){__sync_synchronize();return 0;
}

然后用gcc4.2编译,

# gcc -S -c test.c

然后看对应的汇编代码,

main:pushq %rbpmovq %rsp, %rbpmovl $0, %eaxleaveret

嗯?Nothing at all !!! 不信你试一试,我的编译环境是Freebsd 9.0 release, gcc (GCC) 4.2.1 20070831 patched [FreeBSD]。 好,我换个高版本的gcc编译器试一试,gcc46 (FreeBSD Ports Collection) 4.6.3 20120113 (prerelease)

main:pushq %rbpmovq %rsp, %rbpmfencemovl $0, %eaxpopq %rbpret

看,多了一行,mfence。 怎么回事呢?这是gcc之前的一个BUG:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36793 。 2008年被发现,然后修复的。其实它之所以是一个BUG,关键在于gcc的开发者很迷惑,mfence在x86 CPU上到底有没有用?有嘛用? 说到这里,我们得到一个结论:gcc的__sync_synchronize()尽量别用,因为你的代码在低版本的gcc下会有BUG。大部分人用的gcc都比4.4低。从CentOS 6开始,默认的编译器才是gcc 4.4。

那么mfence到底能不能提供我们想要的结果呢? 之前intel的手册一直语焉不详,没说清楚。

最新的手册对mfence的解释是:

“Serializes all store and load operations that occurred prior to the MFENCE instruction in the 
program instruction stream”

并且特别强调,这个指令影响的是data memory子系统,而不是指令执行流。

对于单个CPU来说,

"Reads cannot pass earlier MFENCE instructions”

“Writes cannot pass earlier MFENCE instructions. ”

“MFENCE instructions cannot pass earlier reads or writes”

而对于多个CPU来说,

• Individual processors use the same ordering principles as in a single-processor system.

• Writes by a single processor are observed in the same order by all processors.

• Writes from an individual processor are NOT ordered with respect to the writes from other processors.

• Memory ordering obeys causality (memory ordering respects transitive visibility).

• Any two stores are seen in a consistent order by processors other than those performing the stores

简单点说,对于单个CPU,即便你不用mfence,写入顺序也是保证的。

假如你在C++中, std::string* str=new std::string();

那么不会出现str指针已经被赋值但是它指向的对象还未被初始化好的情况。

另一个有趣的问题是,gcc有一个汇编指令是用来控制内存顺序的,请看这段文档:

Accesses to non-volatile objects are not ordered with respect to volatile accesses. You cannot use a volatile object as a memory barrier to order a sequence of writes to non-volatile memory. For instance:

     int *ptr = something;volatile int vobj;*ptr = something;     vobj = 1; 

Unless *ptr and vobj can be aliased, it is not guaranteed that the write to *ptr occurs by the time the update of vobj happens. If you need this guarantee, you must use a stronger memory barrier such as:

     int *ptr = something;     volatile int vobj;      *ptr = something;     asm volatile ("" : : : "memory");    vobj = 1;

经我测试,asm volatile (“” : : : “memory”);并不生成任何汇编代码。也就是说,这个仅仅是给编译器看的。

为了进一步证实我的观点,请看如下从Intel的Threading Building Blocks函数库中摘取的代码:

#define __TBB_compiler_fence() __asm__ __volatile__(“”: : :”memory”)
#define __TBB_control_consistency_helper() __TBB_compiler_fence()
#define __TBB_acquire_consistency_helper() __TBB_compiler_fence()
#define __TBB_release_consistency_helper() __TBB_compiler_fence()

#ifndef __TBB_full_memory_fence
#define __TBB_full_memory_fence() __asm__ __volatile__(“mfence”: : :”memory”)
#endif

能同时起编译器和硬件内存屏障作用的是__asm__ __volatile__(“mfence”: : :”memory”)。注意:mfence!

另外,我们在intel cpu上用的CAS指令都是带lock前缀的。所以在使用CAS的时候完全不必考虑memory order的问题。

最后推荐一篇文章:《Mathematizing C++ Concurrency》http://www.cl.cam.ac.uk/~pes20/cpp/popl085ap-sewell.pdf 第一作者是剑桥的某在读博士。)

 

This article is from: https://www.sunchangming.com/blog/post/1632.html

这篇关于Linux __sync_synchronize的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

ubuntu16.04如何部署dify? 在Linux上安装部署Dify的技巧

《ubuntu16.04如何部署dify?在Linux上安装部署Dify的技巧》随着云计算和容器技术的快速发展,Docker已经成为现代软件开发和部署的重要工具之一,Dify作为一款优秀的云原生应用... Dify 是一个基于 docker 的工作流管理工具,旨在简化机器学习和数据科学领域的多步骤工作流。它

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Linux系统调试之ltrace工具使用与调试过程

《Linux系统调试之ltrace工具使用与调试过程》:本文主要介绍Linux系统调试之ltrace工具使用与调试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、ltrace 定义与作用二、ltrace 工作原理1. 劫持进程的 PLT/GOT 表2. 重定

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完