-
(1)内存管理主要功能: 内存分配,内存保护,地址映射和内存扩充等.主要任务: 内存分配的主要任务是为每道程序分配内存空间,提高存储器利用率,以减少不可用的内存空间,允许正在运行的程序申请附加的内存空间,以适应程序和数据动态增长的需要. 内存保护的主要任务是确保每道用户程序都在自己的内存空间中运行,互不干扰. 地址映射的主要任务是将地址空间中的逻辑地址转换为内存空间中与之对应的物理地址. 内存扩充的主要任务是借助虚拟存储技术,从逻辑上去扩充内存容量. (2)处理机管理主要功能: 进程控制,进程同步,进程通信和调度. 主要任务: 进程控制:为作业创建进程,撤销已结束的进程,以及控制进程在运行过程中的状态转换. 进程同步:对诸进程的运行进行调节. 进程通信:实现在相互合作进程之间的信息交换. 调度分为作业调度和进程调度. 作业调度基本任务:从后备队列中按照一定的算法,选择出若干个作业,为它们分配必要的资源; 进程调度的任务:从进程的就绪队列中,按照一定的算法选出一新进程,把处理机分配给它,并为它设置运行现场,是进程投入运行. (3)设备管理主要功能:缓冲管理,设备分配和设备处理,以及虚拟设备等.主要任务:完成用户提出的I/O请求,为用户分配I/O设备;提高CPU和I/O设备的利用率;提高I/O速度;以及方便用户使用I/O设备. 缓冲管理:提高CPU的利用率进而提高系统的吞吐量 设备分配:根据用户进程的I/O请求、系统的现有资源以及按照某种设备的分配策略,为之 分配其所需的设备 设备处理:用于实现CPU和设备控制器之间的通信(4)文件管理主要功能:对文件存储空间的管理,目录管理,文件的读,写管理以及文件的共享和保护.主要任务:对用户文件和系统文件进行管理,以方便用户使用,并保证文件的安全性.
-
RAID概念与实现方式 RAID(Redundant Array of Independent Disks):独立冗余磁盘阵列,简称磁盘阵列。RAID是按照一定的形式和方案组织起来的存储设备,它比单个存储设备在速度、稳定性和存储能力上都有很大提高,并且具备一定的数据安全保护能力。RAID 的主要实现方式分为硬件RAID 方式和软件RAID 方式:硬件RAID:利用集成了处理器的硬件RAID适配卡来对RAID任务进行处理,无须占用主机CPU资源。软RAID:通过软件技术实现,需要操作系统支持,一般不能对系统磁盘实现RAID功能。RAID数据保护机制---热备与重构热备(Hot Spare):当冗余的RAID阵列中某个磁盘失效时,在不干扰当前RAID系统正常使用的情况下,用RAID系统中另外一个正常的备用磁盘顶替失效磁盘。热备通过配置热备盘实现,热备盘分为全局热备盘和局部热备盘RAID5:分布式奇偶校验的独立磁盘结构 从它的示意图上可以看到,它的奇偶校验码存在于所有磁盘上,其中的p0代表第0带区的奇偶校验值,其它的意思也相同。RAID5的读出效率很高,写入效率一般,块式的集体访问效率不错。因为奇偶校验码在不同的磁盘上,所以提高了可靠性。但是它对数据传输的并行性解决不好,而且控制器的设计也相当困难。RAID 3 与RAID 5相比,重要的区别在于RAID 3每进行一次数据传输,需涉及到所有的阵列盘。而对于RAID 5来说,大部分数据传输只对一块磁盘操作,可进行并行操作。在RAID 5中有“写损失”,即每一次写操作,将产生四个实际的读/写操作,其中两次读旧的数据及奇偶信息,两次写新的数据及奇偶信息。1.在VM中新建了三块200M的硬盘.用于实验.如下图所示:2.查看当前系统识别到的磁盘设备#查看当前系统识别到的磁盘设备cat /proc/partitions 3.用fdisk命令初始化三块新硬盘,设置如下图所示:fdisk /dev/sdc4.RAID5磁盘阵列的硬盘使用情况.如下图所示:fdisk -l5、开始创建磁盘阵列mdadm --creat /dev/md0 --level=5 --raid-devices=3 /dev/sd{c,d,e}16、为新建的/dev/md0建立类型为ext3的文件系统mkfs –t ext3 –c /dev/md07、查看创建效果mdadm --detail /dev/md08、新建目录mkdir /mnt/raid5xmount /dev/md0 /mnt/raid5x9、拷贝文件到磁盘阵列cp 任意文件 /mnt/raid5xll /mnt/raid5x10、实现服务器启动自动挂载磁盘阵列vi /etc/fstab重启之后md0自动变为md127,需要重新进入VI修改为md127重启后最终验证
-
一、高速缓存处理器从寄存器文件中读数据比从主存中读取几乎要快100倍。并且随着半导体技术的进步,这种处理器与主存之间的差距还在持续增大。加快处理器的运行速度比加快主存的运行速度要容易和便宜得多。针对这种处理器与主存之间的差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(Cache memory,简称为Cache或高速缓存),作为暂时的集结区域,存放处理器近期可能会需要的信息。 1.根据机械原理,较大的存储设备比较小的存储设备运行得慢,而快速设备的造价远高于同类的低速设备。比如说,一个典型系统上的磁盘驱动器可能比主存大1000倍,但对处理器而言,从磁盘驱动器上读取一个字的时间开销要比从主存中读取的开销大1000万倍。 2.类似地,一个典型的寄存器文件只存储几百字节的信息,而主存里可存放几十亿字节。然而,处理器从寄存器文件中读数据比从主存中读取几乎要快100倍。并且随着这些年半导体技术的进步,这种处理器与主存之间的差距还在持续增大。加快处理器的运行速度比加快主存的运行速度要容易和便宜得多。 3.针对这种处理器与主存之间的差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器( Cache memory,简称为Cache或高速缓存),作为暂时的集结区域,存放处理器近期可能会需要的信息。 4.如图展示了一个典型系统中的高速缓存存储器。位于处理器芯片上的L1高速缓存的容量可以达到数万字节,访问速度几乎和访问寄存器文件一样快。一个容量为数十万到数百万字节的更大的L2高速缓存通过一条特殊的总线连接到处理器。进程访问L2高速缓存的时间要比访问L1高速缓存的时间长5倍,但是这仍然比访问主存的时间快5~10倍。L1和L2高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。 5.比较新的、处理能力更强大的系统甚至有三级高速缓存:L1、L2和L3。系统可以获得一个很大的存储器,同时访问速度也很快,原因是利用了高速缓存的局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能在快速的高速缓存中完成二、存储设备层次结构 每个计算机系统中的存储设备都被组织成了一个存储器层次结构。在这个层次结构中,从上至下,设备的访问速度越来越慢、容量越来越大,并且每字节的造价也越来越便宜。寄存器文件在层次结构中位于最顶部,也就是第o级或记为LO。 在处理器和一个较大较慢的设备(例如主存)之间插入一个更小更快的存储设备(例如高速缓存)的想法已经成为一个普遍的观念。实际上,每个计算机系统中的存储设备都被组织成了一个存储器层次结构,如图所示。在这个层次结构中,从上至下,设备的访问速度越来越慢、容量越来越大,并且每字节的造价也越来越便宜。寄存器文件在层次结构中位于最顶部,也就是第O级或记为L0。这里我们展示的是三层高速缓存L1到L3,占据存储器层次结构的第1层到第3层。主存在第4层,以此类推。存储器层次结构的主要思想是上一层的存储器作为低一层存储器的高速缓存。因此,寄存器文件就是L1的高速缓存,L1是L2的高速缓存,L2是L3的高速缓存,L3是主存的高速缓存,而主存又是磁盘的高速缓存。在某些具有分布式文件系统的网络系统中,本地磁盘就是存储在其他系统中磁盘上的数据的高速缓存正如可以运用不同的高速缓存的知识来提高程序性能一样,程序员同样可以利用对整个存储器层次结构的理解来提高程序性能。三、多核处理器内存层次结构 多核处理器可以将多个CPu集成到一个集成电路芯片上。对于多核处理器,每个核都有自己的L1和L2高速缓存,其中的L1高速缓存分为两个部分,一部分保存最近取到的指令,另一部分存放数据。 多核处理器是将多个CPU(称为“核")集成到一个集成电路芯片上。图中描述的是一个典型多核处理器的组织结构,其中微处理器芯片有4个CPu核,每个核都有自己的L1和L2高速缓存,其中的L1高速缓存分为两个部分一个保仔最近取到的指令,力一个存放数据。这些核共享更高层次的高速缓存,以及到主存的接口。工业界的专家预言他们能够将几十个、最终会是上百个核做到一个芯片上。
-
fdisk命令用途:在交互式的操作环境中管理磁盘分区格式:fdisk [磁盘设备]磁盘管理-->块设备文件 b开头-->/dev/ 对于linux系统磁盘命名: IDE接口的硬盘为 hda hdb SAS,SATA,SCSI接口的硬盘 sda 分区sda1 sda2 sdb主引导记录(MBR):位于磁盘的第一个扇区 521字节=446字节 引导程序 记录4个分区表,每个16字节,64字节 还有2个校验字节fdisk磁盘管理工具-l查看所有磁盘信息n创建新分区d删除分区p列出分区表w把分区表写入硬盘并退出e扩展分区Blocks:分区的大小,以Blocks(块)为单位,默认的块大小为1024字节。Id:分区类型的ID标记号,对于EXT3分区为83,LVM分区为8eMBR中只可以划分4个主分区,或者时3个主分区+1个扩展分区 扩展分区后,可以划分逻辑分区1.fdisk划分分区2.创建文件系统 mkfs.xfs /dev/sdb1(划分) 文件系统:组织和管理文件的 FAT16 FAT32 exFAT u盘使用-->不支持单个超过4G NTFS -->windows使用 ext4/ext3/ext2 -->centos6默认 XFS -->centos7默认 centos6和centos7的区别:默认系统不同mkfs 创建文件系统 -f 强制覆盖,因为系统中主分区加扩展分区占用1-4的分区号,所以第一个逻辑分区为5partprobe刷新分区表df查看系统挂载信息-T显示文件系统类型-h以人类可读方式显示-i查看inode情况Logical Volume Manager,逻辑卷管理作用:动态调整磁盘容量,从而提高磁盘管理的灵活性需要注意:•/boot分区用于存放引导文件,不能基于LVM创建图形界面管理工具•system-config-lvmLVM机制的基本概念PV(Physical Volume,物理卷)• 整个硬盘,或使用fdisk等工具建立的普通分区• 包括许多默认4MB大小的PE(Physical Extent,基本单元)VG(Volume Group,卷组)• 一个或多个物理卷组合而成的整体LV(Logical Volume,逻辑卷)• 从卷组中分割出的一块空间,用于建立文件系统主要命令的语法pvcreate 设备名vgcreate 卷组名 物理卷名1 物理卷名2lvcreate -L 大小 -n 逻辑卷名 卷组名lvextend -L +大小 /dev/卷组名/逻辑卷名
-
Kafka通过topic来分主题存放数据,主题内有分区,分区可以有多个副本,分区的内部还细分为若干个segment。所谓的分区其实就是在Kafka对应存储目录下创建的文件夹,文件夹的名字是主题名加上分区编号。①Topic 一类消息,消息存放的目录即主题,例如page view日志、click日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发。②Partition topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列③Segment 所谓的segment其实就是在分区对应的文件夹下产生的文件。一个分区会被划分成大小相等的若干segment,这样一方面保证了分区的数据被划分到多个文件中保证不会产生体积过大的文件;另-方面可以基于这些segment文件进行历史数据的删除,提高效率。一个segment又由一个log和一个index文件组成。④Log Log由多个Segment文件组成,接收到的新消息永远是以追加的方式于Segment文件中,Segment的文件个数随着数据量的累积而增加,每个消息有自增编号,这种只追加不修改的方式避免了变更前的查询消耗。⑤index Index文件仅记录固定消息量的索引编号范围,Kafka在查询时,先从Index中定位到小范围的索引编号区间,再去Log中在小范围的数据块中查询具体数据,此索引区间的查询方式称为:稀疏索引。二、原理概念1、持久化 kafka使用文件存储消息(append only log),这就直接决定kafka在性能上严重依赖文件系统的本身特性。且无论任何OS下,对文件系统本身的优化是非常艰难的。文件缓存/直接内存映射等是常用的手段。因为kafka是对日志文件进行append操作,因此磁盘检索的开支是较小的;同时为了减少磁盘写入的次数,broker会将消息暂时buffer起来,当消息的个数(或尺寸)达到一定阀值时,再flush到磁盘,这样减少了磁盘IO调用的次数。对于kafka而言,较高性能的磁盘,将会带来更加直接的性能提升。2、性能 除磁盘IO之外,我们还需要考虑网络IO,这直接关系到kafka的吞吐量问题。kafka并没有提供太多高超的技巧;对于producer端,可以将消息buffer起来,当消息的条数达到一定阀值时,批量发送给broker;对于consumer端也是一样,批量fetch多条消息。不过消息量的大小可以通过配置文件来指定。对于Kafka broker端,似乎有个Send file系统调用可以潜在的提升网络IO的性能:将文件的数据映射到系统内存中,socket直接读取相应的内存区域即可,而无需进程再次copy和交换(这里涉及到"磁盘IO数据"、"内核内存"、"进程内存"、"网络缓冲区",多者之间的数据copy)。3、Topic模型 其他JMS实现,消息消费的位置是有provider保留,以便避免重复发送消息或者将没有消费成功的消息重发等,同时还要控制消息的状态。这就要求JMS broker需要太多额外的工作。在kafka中,partition中的消息只有一个consumer在消费,且不存在消息状态的控制,也没有复杂的消息确认机制,可见kafka broker端是相当轻量级的。当消息被consumer接收之后,consumer可以在本地保存最后消息的offset,并间歇性的向zookeeper注册offset。由此可见,consumer客户端也很轻量级。4、负载均衡 kafka集群中的任何一个broker,都可以向producer提供metadata信息,这些metadata中包含"集群中存活的servers列表"/"partitions leader列表"等信息。消息由producer直接通过socket发送到broker,中间不会经过任何"路由层"。 异步发送,将多条消息暂且在客户端buffer起来,并将他们批量发送到broker;小数据IO太多,会拖慢整体的网络延迟,批量延迟发送事实上提升了网络效率;不过这也有一定的隐患,比如当producer失效时,那些尚未发送的消息将会丢失。
-
部署3台ceph 节点,如下:[root@ceph-1 ceph]# cat ceph.conf[global]fsid = 835f6d27-8e03-4f7f-8d21-b0a26993b529mon_initial_members = ceph-1mon_host = 172.24.193.62auth_cluster_required = cephxauth_service_required = cephxauth_client_required = cephxmon_allow_pool_delete=trueosd_pool_default_size = 2[root@ceph-1 ~]# ceph -s cluster: id: 835f6d27-8e03-4f7f-8d21-b0a26993b529 health: HEALTH_OK services: mon: 1 daemons, quorum ceph-1 mgr: ceph-1(active) osd: 3 osds: 3 up, 3 in data: pools: 1 pools, 128 pgs objects: 510 objects, 1.9 GiB usage: 6.8 GiB used, 233 GiB / 240 GiB avail pgs: 128 active+clean[root@ceph-1 ~]# ceph osd status+----+--------+-------+-------+--------+---------+--------+---------+-----------+| id | host | used | avail | wr ops | wr data | rd ops | rd data | state |+----+--------+-------+-------+--------+---------+--------+---------+-----------+| 0 | ceph-1 | 2170M | 77.8G | 0 | 0 | 0 | 0 | exists,up || 1 | ceph-2 | 2376M | 77.6G | 0 | 0 | 0 | 0 | exists,up || 2 | ceph-3 | 2456M | 77.5G | 0 | 0 | 0 | 0 | exists,up |+----+--------+-------+-------+--------+---------+--------+---------+-----------+[root@ceph-1 ceph]# ceph auth lsinstalled auth entries:osd.0 key: AQDH9qNjHRvdDBAAIS8klDI+PhUUSAwlxmEhKA== caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow *osd.1 key: AQDf9qNjNSttFRAA28htGbtUWAYBxK9kacVHXQ== caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow *osd.2 key: AQDu9qNj43mtGRAAJ4tAU5Ie9carFkhRcwnMnQ== caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow *client.admin key: AQC+86NjAev/HRAAD/wXEPaDVlEOWMn0H2x8ng== caps: [mds] allow * caps: [mgr] allow * caps: [mon] allow * caps: [osd] allow *client.bootstrap-mds key: AQC+86NjHAIAHhAAm0L2LXEzwRx7ijTBMlsmSQ== caps: [mon] allow profile bootstrap-mdsclient.bootstrap-mgr key: AQC+86Nj4xEAHhAADcU3pbq04mk4wK8DxNH6hA== caps: [mon] allow profile bootstrap-mgrclient.bootstrap-osd key: AQC+86NjryAAHhAAzCw13oaWl8EvdrVRCqc+wQ== caps: [mon] allow profile bootstrap-osdclient.bootstrap-rbd key: AQC+86NjEDAAHhAAWev9IkV4zd6gSoUjEEK2ZA== caps: [mon] allow profile bootstrap-rbdclient.bootstrap-rgw key: AQC+86NjXz4AHhAADlfczh0/8voJZuDWkHaJ9w== caps: [mon] allow profile bootstrap-rgwclient.libvirt key: AQDULP9jtWHCMxAAfIBCbNynpHADCYMwQr8xpg== caps: [mon] allow r caps: [osd] allow class-read object_prefix rbd_children, allow rwx pool=libvirt-poolmgr.ceph-1 key: AQAF9KNj6Io3OBAAX6koyzKcwSn+IL5IemY3xg== caps: [mds] allow * caps: [mon] allow profile mgr caps: [osd] allow *在ceph client 上创建vm ,使用ceph rbd 访问 ceph pool libvirt-pool里的qcow2 镜像: 43 <emulator>/usr/local/bin/qemu-system-x86_64</emulator> 44 <disk type='network' device='disk'> 45 <driver name='qemu' type='raw' cache='writeback'/> 46 <auth username='libvirt'> 47 <secret type='ceph' uuid='8187dd57-7e0d-4a9d-8e5a-fe5234d40e51'/> 48 </auth> 49 <source protocol='rbd' name='libvirt-pool/root-vsys_c1.qcow2'> 50 <host name='172.24.193.62' port='6789'/> 51 <host name='172.24.193.63' port='6789'/> 52 <host name='172.24.193.64' port='6789'/> 53 </source> 54 <target dev='vda' bus='virtio'/> 55 <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> 56 </disk>在ceph-client 上可以利用 client.libvirt 用户访问 ceph 上的libvirt-pool ,如下:如上图卡了,看样子是找不到启动盘了。。。libvirtd 把 root-vsys_c1 xml 中的 启动 虚拟机的命令如下:[root@ceph-client-65 ceph]# rbd --user libvirt ls libvirt-poolroot-vsys_c1.qcow2而我不通过virsh start xxx 方式启动vm,采取直接qemu 启动,则可以成功进入vm 内部,并正常引导kernel这种方式和virsh 方式的不同点,就是 qemu 没有同ceph 进行cephx 验证吧。本人怀疑是 ceph client 接入ceph 认证导致的,可是我都已经参考了此ceph 官网链接:https://docs.ceph.com/en/quincy/rbd/libvirt/ 反复检查了。在创建vm 的客户端节点上都可以访问ceph 集群内。希望有从事ceph 分布式存储这方面实战经验的高手多多指教下这个现象出现的原因及解决方法。谢谢!
-
创建minio,没配置访问链接的地方,如何配置外部存储的minio?
-
存储位置不同,打包到生产后,开发环境配置的资源获取不到,有没有能通过中间层,或者配置参数的方式,打包到生产能正常调用不同存储的资源?
-
ERROR - 2022-12-07 18:05:29 --> Severity: Warning --> fread(): SSL: Connection reset by peer /dev/third_party/huaweicloud-obs/vendor/guzzlehttp/psr7/src/Stream.php 231ERROR - 2022-12-07 17:32:56 --> Severity: error --> Exception: Argument 1 passed to Obs\ObsClient::Obs\Internal\{closure}() must be an instance of GuzzleHttp\Exception\RequestException, instance of GuzzleHttp\Exception\ConnectException given, called in /dev/third_party/huaweicloud-obs/vendor/guzzlehttp/promises/src/Promise.php on line 204 /dev/third_party/huaweicloud-obs/Obs/Internal/SendRequestTrait.php 640
-
迁移环境:操作系统: CentOS Linux release 7.6.1810 (AltArch) Linux ### 4.14.0-115.el7a.0.1.aarch64 #1 SMP Sun Nov 25 20:54:21 UTC 2018 aarch64 aarch64 aarch64 GNU/Linux组件: tfs(开源地址:https://github.com/alibaba/tfs/tree/release-2.2.13)依赖:jemalloc,mysql-connector-c,zlib-devel,libuuid,libtbsys.so,libtbnet.so(后两个的迁移案例:https://bbs.huaweicloud.com/forum/thread-102614-1-1.html)迁移过程:里面的脚本等小错误还是比较多的,但这些都不是重点,稍微修改一下就好(后面附带修改后的完整代码),来看看一下报错 unknown mnemonic 'lock' -- 'lock' unknown mnemonic 'xaddl' -- xaddl x20,[x0] unknown mnemonic 'lock' -- 'lock' unknown mnemonic 'xaddl' -- xaddl x7,[x1]错误类似上一篇https://bbs.huaweicloud.com/forum/thread-102614-1-1.html我们接着看具体的代码:src/common/atomic.h-----------------------------------------------------------------------------------------------------#if defined(__i386__) || defined(__x86_64__) // Atomic operations that C can't guarantee us. Useful for // resource counting etc.. // SMP lock prefix #ifdef CONFIG_SMP #define LOCK_PREFIX "lock ; " #else #define LOCK_PREFIX "" #endif //return: the incremented value; /// 原子地做 8位,16位,32位,64位的++i的操作 /// 该操作虽然参数和返回值都是无符号型整数,但是一样可以 /// 对有符号型整数做操作,只需要做适当的参数转换即可 /// @param pv 指向操作数的指针 /// @return 操作数加1以后的数值 #ifdef __x86_64__ static __inline__ uint64_t atomic_inc(volatile uint64_t * pv) { register unsigned long __res; __asm__ __volatile__ ( "movq $1,%0;" LOCK_PREFIX "xaddq %0,(%1);" "incq %0" :"=a" (__res), "=q" (pv): "1" (pv)); return __res; } #endif static __inline__ uint32_t atomic_inc(volatile uint32_t * pv) { register unsigned int __res; __asm__ __volatile__ ( "movl $1,%0;" LOCK_PREFIX "xaddl %0,(%1);" "incl %0" :"=a" (__res), "=q" (pv): "1" (pv)); return __res; } static __inline__ uint16_t atomic_inc(volatile uint16_t * pv) { register unsigned short __res; __asm__ __volatile__ ( "movw $1,%0;" LOCK_PREFIX "xaddw %0,(%1);" "incw %0" :"=a" (__res), "=q" (pv): "1" (pv)); return __res; } static __inline__ uint8_t atomic_inc(volatile uint8_t * pv) { register unsigned char __res; __asm__ __volatile__ ( "movb $1,%0;" LOCK_PREFIX "xaddb %0,(%1);" "incb %0" :"=a" (__res), "=q" (pv): "1" (pv)); return __res; } //return: the decremented value; /// 原子地做 8位,16位,32位,64位的--i的操作 /// 该操作虽然参数和返回值都是无符号型整数,但是一样可以 /// 对有符号型整数做操作,只需要做适当的参数转换即可 /// @param pv 指向操作数的指针 /// @return 操作数减1后的数值 #ifdef __x86_64__ static __inline__ uint64_t atomic_dec(volatile uint64_t * pv) { register unsigned long __res; __asm__ __volatile__ ( "movq $0xffffffffffffffff,%0;" LOCK_PREFIX "xaddq %0,(%1);" "decq %0" : "=a" (__res), "=q" (pv): "1" (pv)); return __res; } #endif static __inline__ uint32_t atomic_dec(volatile uint32_t * pv) { register unsigned int __res; __asm__ __volatile__ ( "movl $0xffffffff,%0;" LOCK_PREFIX "xaddl %0,(%1);" "decl %0" : "=a" (__res), "=q" (pv): "1" (pv)); return __res; } static __inline__ uint16_t atomic_dec(volatile uint16_t * pv) { register unsigned short __res; __asm__ __volatile__ ( "movw $0xffff,%0;" LOCK_PREFIX "xaddw %0,(%1);" "decw %0" : "=a" (__res), "=q" (pv): "1" (pv)); return __res; } static __inline__ uint8_t atomic_dec(volatile uint8_t * pv) { register unsigned char __res; __asm__ __volatile__ ( "movb $0xff,%0;" LOCK_PREFIX "xaddb %0,(%1);" "decb %0" : "=a" (__res), "=q" (pv): "1" (pv)); return __res; } //return: the initial value of *pv /// 原子地做 8位,16位,32位,64位的加法的操作 /// 该操作虽然参数和返回值都是无符号型整数,但是一样可以 /// 对有符号型整数做操作,只需要做适当的参数转换即可 /// @param pv 指向操作数的指针 /// @return 操作数加法之前的数值 #ifdef __x86_64__ static __inline__ uint64_t atomic_add(volatile uint64_t * pv, const uint64_t av) { //:"=a" (__res), "=q" (pv): "m"(av), "1" (pv)); register unsigned long __res; __asm__ __volatile__ ( "movq %2,%0;" LOCK_PREFIX "xaddq %0,(%1);" :"=a" (__res), "=q" (pv): "mr"(av), "1" (pv)); return __res; } #endif static __inline__ uint32_t atomic_add(volatile uint32_t * pv, const uint32_t av) { //:"=a" (__res), "=q" (pv): "m"(av), "1" (pv)); register unsigned int __res; __asm__ __volatile__ ( "movl %2,%0;" LOCK_PREFIX "xaddl %0,(%1);" :"=a" (__res), "=q" (pv): "mr"(av), "1" (pv)); return __res; } static __inline__ uint16_t atomic_add(volatile uint16_t * pv, const uint16_t av) { //:"=a" (__res), "=q" (pv): "m"(av), "1" (pv)); register unsigned short __res; __asm__ __volatile__ ( "movw %2,%0;" LOCK_PREFIX "xaddw %0,(%1);" :"=a" (__res), "=q" (pv): "mr"(av), "1" (pv)); return __res; } static __inline__ uint8_t atomic_add(volatile uint8_t * pv, const uint8_t av) { //:"=a" (__res), "=q" (pv): "m"(av), "1" (pv)); register unsigned char __res; __asm__ __volatile__ ( "movb %2,%0;" LOCK_PREFIX "xaddb %0,(%1);" :"=a" (__res), "=q" (pv): "mr"(av), "1" (pv)); return __res; } //function: set *pv to nv //return: the initial value of *pv /// 原子地把nv赋值给pv指向的整数,支持8位,16位,32位,84位操作 /// @param pv 待赋值的整数(目的操作数) /// @param nv 向pv赋的整数 /// @return pv指向的赋值前的数值 #ifdef __x86_64__ static __inline__ uint64_t atomic_exchange(volatile uint64_t * pv, const uint64_t nv) { register unsigned long __res; __asm__ __volatile__ ( "1:" LOCK_PREFIX "cmpxchgq %3,(%1);" \ "jne 1b": "=a" (__res), "=q" (pv): "1" (pv), "q" (nv), "0" (*pv)); return __res; } #endif static __inline__ uint32_t atomic_exchange(volatile uint32_t * pv, const uint32_t nv) { register unsigned int __res; __asm__ __volatile__ ( "1:" LOCK_PREFIX "cmpxchgl %3,(%1);" \ "jne 1b": "=a" (__res), "=q" (pv): "1" (pv), "q" (nv), "0" (*pv)); return __res; } static __inline__ uint16_t atomic_exchange(volatile uint16_t * pv, const uint16_t nv) { register unsigned short __res; __asm__ __volatile__ ( "1:" LOCK_PREFIX "cmpxchgw %3,(%1);" \ "jne 1b": "=a" (__res), "=q" (pv): "1" (pv), "q" (nv), "0" (*pv)); return __res; } static __inline__ uint8_t atomic_exchange(volatile uint8_t * pv, const uint8_t nv) { register unsigned char __res; __asm__ __volatile__ ( "1:" LOCK_PREFIX "cmpxchgb %3,(%1);" \ "jne 1b": "=a" (__res), "=q" (pv): "1" (pv), "q" (nv), "0" (*pv)); return __res; } //function: compare *pv to cv, if equal, set *pv to nv, otherwise do nothing. //return: the initial value of *pv /// 比较pv和cv,如果两者相等,则返回pv原有数值并且把nv赋值给pv /// 否则什么也不作,返回pv原有数值 /// @param pv 待赋值的整数(目的操作数) /// @param nv 向pv赋的整数 /// @param cv 和pv比较的整数 /// @return pv指向的操作前的数值 #ifdef __x86_64__ static __inline__ uint64_t atomic_compare_exchange(volatile uint64_t * pv, const uint64_t nv, const uint64_t cv) { register unsigned long __res; __asm__ __volatile__ ( LOCK_PREFIX "cmpxchgq %3,(%1)" : "=a" (__res), "=q" (pv) : "1" (pv), "q" (nv), "0" (cv)); return __res; } #endif static __inline__ uint32_t atomic_compare_exchange(volatile uint32_t * pv, const uint32_t nv, const uint32_t cv) { register unsigned int __res; __asm__ __volatile__ ( LOCK_PREFIX "cmpxchgl %3,(%1)" : "=a" (__res), "=q" (pv) : "1" (pv), "q" (nv), "0" (cv)); return __res; } static __inline__ uint16_t atomic_compare_exchange(volatile uint16_t * pv, const uint16_t nv, const uint16_t cv) { register unsigned short __res; __asm__ __volatile__ ( LOCK_PREFIX "cmpxchgw %3,(%1)" : "=a" (__res), "=q" (pv) : "1" (pv), "q" (nv), "0" (cv)); return __res; } static __inline__ uint8_t atomic_compare_exchange(volatile uint8_t * pv, const uint8_t nv, const uint8_t cv) { register unsigned char __res; __asm__ __volatile__ ( LOCK_PREFIX "cmpxchgb %3,(%1)" : "=a" (__res), "=q" (pv) : "1" (pv), "q" (nv), "0" (cv)); return __res; } typedef void * pvoid; //function: set *pv to nv //return: the initial value of *pv /// 把nv原子地赋值给*pv static __inline__ pvoid atomic_exchange_pointer(volatile pvoid * pv, const pvoid nv) { #ifdef __x86_64__ return (pvoid) atomic_exchange((uint64_t *) pv, (uint64_t) nv); #else return (pvoid) atomic_exchange((uint32_t *) pv, (uint32_t) nv); #endif } //function: compare *pv to cv, if equal, set *pv to nv, otherwise do nothing. //return: the initial value of *pv /// 比较cv和*pv,如果两者相等则把nv赋值给*pv,并且返回*pv原有数值 /// 否则返回*pv原有数值,不做赋值操作 static __inline__ pvoid atomic_compare_exchange_pointer(volatile pvoid * pv, const pvoid nv, const pvoid cv) { #ifdef __x86_64__ return (pvoid) atomic_compare_exchange((uint64_t *) pv, (uint64_t) nv, (uint64_t)cv); #else return (pvoid) atomic_compare_exchange((uint32_t *) pv, (uint32_t) nv, (uint32_t)cv); #endif } #undef LOCK_PREFIX好嘛,又是定义x86下的asm函数,好吧,继续使用gcc的内建__sync的原子操作函数来做实现,修改后的文件如下:
上滑加载中
推荐直播
-
DTT年度收官盛典:华为开发者空间大咖汇,共探云端开发创新
2025/01/08 周三 16:30-18:00
Yawei 华为云开发工具和效率首席专家 Edwin 华为开发者空间产品总监
数字化转型进程持续加速,驱动着技术革新发展,华为开发者空间如何巧妙整合鸿蒙、昇腾、鲲鹏等核心资源,打破平台间的壁垒,实现跨平台协同?在科技迅猛发展的今天,开发者们如何迅速把握机遇,实现高效、创新的技术突破?DTT 年度收官盛典,将与大家共同探索华为开发者空间的创新奥秘。
回顾中 -
GaussDB应用实战:手把手带你写SQL
2025/01/09 周四 16:00-18:00
Steven 华为云学堂技术讲师
本期直播将围绕数据库中常用的数据类型、数据库对象、系统函数及操作符等内容展开介绍,帮助初学者掌握SQL入门级的基础语法。同时在线手把手教你写好SQL。
去报名 -
算子工具性能优化新特性演示——MatMulLeakyRelu性能调优实操
2025/01/10 周五 15:30-16:00
周老师 昇腾讲师
算子工具性能优化新特性演示——MatMulLeakyRelu性能调优实操
即将直播
热门标签