参考书《Linux内核模块开发技术指南》

1.原理

在多核CPU的情况下,为了提高CPU并发执行的效率,对于某些不是必须要在核间进行同步访问的资源,可以为每一个CPU创建一个副本,让每个CPU都访问自身的数据副本,而不是通过加锁等互斥手段访问内存中的同一数据,这样可以提高并发执行效率。例如:操作系统中有很多个进程,这些进程会在队列中,等待调度到某个CPU上运行,如果将这些进程放在一个队列中,各CPU需要访问这个队列并从队列取出进程运行时,则需要加锁操作以进行多核间的访问互斥,如下图所示。
在这里插入图片描述

由于访问进程所在的队列时需要加锁,上图中的四个CPU会发生资源竞争。同一时刻如果多个CPU想要同时访问队列,则只能有一个CPU能够访问成功,其他CPU则会等待,直到访问队列的CPU退出访问(这样的方式效率不高)。此时,如果创建多个队列,队列的数量和CPU核心数相同,一个队列和一个CPU绑定。让所有进程均匀分散在各队列中,而每个CPU只访问和自身绑定的队列,这时由于各队列是CPU的私有数据,CPU不会访问到不和自身绑定的队列,就不用通过加锁进行资源互斥,如此可大大提高运行效率。如下图所示。
在这里插入图片描述
以上描述的为每个CPU都创建一个私有数据副本的方式被称为PER_CPU。除了无需加锁外,PER_CPU还可以提高CPU的Cache利用。如果某些资源不是必须要在核间进行同步访问,使用PER_CPU是一个好的选择。需要注意的是,使用PER_CPU并不是意味着在任何情况下都无需进行加锁,在上图中,如果一个进程从CPU的私有队列迁移到另一个CPU的私有队列中,是需要加锁进行互斥的,因为这涉及到跨CPU的资源访问。

2.相关接口

开发人员能够通过内核提供的接口使用PER_CPU机制,这些接口在内核源码的include/linux/percpu-defs.h头文件和include/linux/percpu.h头文件中声明。这里将其分为两组接口:静态声明PER_CPU接口和动态分配PER_CPU接口。
(1)静态声明
PER_CPU的静态声明接口指的是PER_CPU变量使用的内存空间在编译期间分配,这些接口如下所示。

DECLARE_PER_CPU(type, name)

该接口用于创建PER_CPU变量。第一个参数type是变量类型,第二个参数name是变量名。例如要为每个CPU分配一个类型为long,变量名为test的变量,通过DECLARE_PER_CPU(long, test)可以实现。

DEFINE_PER_CPU(type, name)

该接口用于声明PER_CPU变量,参数和DECLARE_PER_CPU的参数一致。

get_cpu_var(var)

该接口用于获取当前CPU的PER_CPU变量,参数var是变量名,返回值是对应的PER_CPU变量。

put_cpu_var(var)

该接口和get_cpu_var配合使用,在PER_CPU变量访问完成时调用。
(2)动态分配
PER_CPU的动态分配指的是PER_CPU变量的内存空间在内核运行期间动态分配,相关接口如下所示。

alloc_percpu(type)

该接口用于分配PER_CPU变量,参数type是变量类型。函数的返回值就是分配的PER_CPU指针变量。

void free_percpu(void __percpu *__pdata)

该接口用于释放PER_CPU变量,其参数是PER_CPU的指针变量,一般由alloc_percpu分配。

per_cpu_ptr(ptr, cpu)

该接口用于获取某个CPU的私有PER_CPU变量。第一个参数ptr是PER_CPU变量,一般由alloc_percpu分配。第二个参数cpu是CPU编号。执行完该接口后,返回的就是编号为cpu的处理器的私有PER_CPU指针变量。

3.示例程序

本节通过一个简单的示例程序来说明如何使用PER_CPU的接口。假设PC上有两个CPU,分别为CPU0和CPU1,示例程序通过alloc_percpu分配一个PER_CPU变量,然后通过per_cpu_ptr分别获取并设置两个CPU对应的PER_CPU变量的值,然后将两个CPU的PER_CPU变量的值分别打印出来。源码如下:

#include <linux/module.h>
#include <linux/percpu.h>//要使用PER_CPU相关接口需引入该头文件
//自定义结构体
struct my_test_struct
{int a;
};
//声明一个类型为my_test_struct的PER_CPU变量
static struct my_test_struct *percpu_test; 
//加载函数
static int test_percpu_init(void)
{
//动态分配PER_CPU变量
percpu_test = alloc_percpu(struct my_test_struct);  per_cpu_ptr(percpu_test, 0)->a = 1;  //将CPU0中的变量a的值设为1per_cpu_ptr(percpu_test, 1)->a = 2;  //将CPU1中的变量a的值设为2
//分别打印出两个CPU的PER_CPU变量值printk("cpu 0:a=%d\n", per_cpu_ptr(percpu_test, 0)->a);printk("cpu 1:a=%d\n", per_cpu_ptr(percpu_test, 1)->a);return 0;
}
//卸载函数
static void test_percpu_exit(void)
{free_percpu(percpu_test);      //释放分配的PER_CPU变量
}
module_init(test_percpu_init);
module_exit(test_percpu_exit);
MODULE_LICENSE("GPL");          //要使用PER_CPU变量需要声明GPL许可协议

编译、加载上述模块后,执行dmesg -c命令打印调试信息,会分别打印出两个CPU的PER_CPU变量值,这两个值分别为1和2。如下图所示。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VSCode 的百度 AI编程插件

VSCode 的百度 AI编程插件主要是 Baidu Comate&#xff08;文心快码&#xff09;&#xff0c;这是一款基于文心大模型的新一代编码辅助工具&#xff0c;旨在提升开发者的编码效率&#xff0c;让写代码变得更简单。以下是关于 Baidu Comate 的详细介绍&#xff1a; 一、功能特点…

阿里云监控使用

阿里云的云监控服务&#xff08;CloudMonitor&#xff09;是一款简单易用、功能强大的监控工具&#xff0c;主要用来帮助用户实时监控阿里云上的各种资源&#xff08;比如服务器、数据库、网络等&#xff09;&#xff0c;并在出现问题时及时发出警报&#xff0c;确保业务稳定运…

嵌入式C语言-关键字typedef

定义和作用 typedef是C/C中的一个关键字&#xff0c;作用是为现有的数据类型&#xff08;int 、char 、flaot等&#xff09;创建新的别名&#xff0c;其目的是为了方便阅读和理解代码。 用法 typedef 原有类型名 新类型名;基本类型创建别名 typedef unsigned char uint8_t; typ…

【混合开发】【大前端++】Vue节点优化Dome之单节点轮播图片播放视频二

动图更精彩 背景 Vue作为大前端开发页面交互&#xff0c;在数字屏&#xff0c;智慧大屏等大屏幕开发过程中&#xff0c;轮播效果作为丰富的展示组件经常作为首选。但也因为这个组件的交互体验很好&#xff0c;于是各种单点组件增加到轮播效果里。经过业务的扩展&#xff0c;人…

前端开发核心技术与工具全解析:从构建工具到实时通信

觉得主包文章可以的,可以点个小爱心哟&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 主页:一位搞嵌入式的 genius-CSDN博客 系列文章专栏: https://blog.csdn.net/m0_73589512/category_13028539.html 前端开发核心技术与工具全解…

GPT 系列论文 gpt3-4 175B参数 + few-shot + 多模态输入 + RLHF + system

GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【论文精读】 GPT-4论文精读 从1750亿参数的文本预言家&#xff0c;到多模态的通用天才&#xff0c;OpenAI用两次震撼世界的发布&#xff0c;重新定义了人工智能的可能性边界。这份笔记将带你深入GPT-3和GPT-4的核心突破&#…

.gitignore文件的作用及用法

目录 ​​.gitignore 文件的作用​​ ​​.gitignore 的基本语法​​ ​​Python 项目的 .gitignore 示例​​ ​​如何使用 .gitignore​​ ​​1. 创建 .gitignore 文件​​ ​​2. 编辑 .gitignore​​ ​​3. 检查 Git 状态​​ ​​常见问题​​ ​​Q1&#xff…

QEMU环境准备

QEMU环境准备 下载 qemu # qemu sudo apt install qemu-system-arm # gdb sudo apt install gdb-multiarchsudo apt-get update sudo apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev \libpixman-1-dev libfdt-dev ninja-build下载并自行编译 qemu(可…

003 cargo使用

cargo是什么 cargo 是 Rust 的构建系统和包管理器。Rust 开发者常用 cargo 来管理 Rust 工程和获取工程所依赖的库。 在上一篇文章中我们已经使用cargo new命令创建了一个名叫hello_rust的项目。也使用cargo run来运行项目。 cargo常用命令 cargo 除了创建工程以外还具备构建&a…

跨省跨国监控难题破解:多层级运维的“中国解法”

在全球化的商业浪潮中&#xff0c;集团型客户的业务布局日益广泛&#xff0c;涉及跨省甚至跨国的多个分支机构和业务节点。这种跨域管理的模式给企业的运维监控带来了前所未有的挑战。多个分支机构和业务节点运维调整首先&#xff0c;不同地区的网络环境差异巨大。从国内不同省…

pandas读取复合列名列头及数据和处理

pandas读取复合列名列头及数据和处理1. 效果图2. 源代码1. 效果图 原始excel&#xff1a; 读取1&#xff0c;2行为复合表头&#xff1a; 读取序号为1003一整行的数据&#xff0c;以及获取序号为1002行及1003行的C列复合表头列的值&#xff1a; 2. 源代码 import pandas …

制作一个简单的vscode插件

当前环境情况 操作系统&#xff1a;Windows 项目类型&#xff1a;VS Code 插件&#xff08;TypeScript 编写&#xff09; Node.js 版本&#xff1a;20.18.1 yarn 版本&#xff1a;1.22.22 npm 版本&#xff1a;10.8.2 npm registry&#xff1a;huawei ------- https://repo.hua…

分布式专题——10.2 ShardingSphere-JDBC分库分表实战与讲解

1 分库分表案例 下面实现一个分库分表案例&#xff0c;将一批课程信息分别拆分到两个库&#xff0c;四个表中&#xff1a; 需提前准备一个 MySQL 数据库&#xff0c;并在其中创建 Course 表。Course 表的建表语句如下&#xff1a; CREATE TABLE course (cid bigint(0) NOT N…

Digital Clock 4,一款免费的个性化桌面数字时钟

Digital Clock 4&#xff0c;一款免费的个性化桌面数字时钟 ** 功能 ** &#xff1a;一款免费的桌面数字时钟工具&#xff0c;支持多种皮肤、透明度调节和字体样式自定义&#xff0c;时钟可自由拖动&#xff0c;支持设置闹钟、定时关机、显示自定义消息等功能&#xff0c;适合想…

学习Python是一个循序渐进的过程,结合系统学习、持续实践和项目驱动,

学习Python是一个循序渐进的过程&#xff0c;结合系统学习、持续实践和项目驱动&#xff0c;你会掌握得更好。下面我为你梳理了一个分阶段的学习路线和实用建议&#xff0c;希望能帮你高效入门并逐步提升。 &#x1f40d; Python学习指南&#xff1a;从入门到精通 &#x1f5…

vcpkg:面向C/C++的跨平台库管理工具软件配置笔记经验教程

1、什么是vcpkg 对于使用过Python进行程序设计的开发者们&#xff0c;大多都会对Python的各种库和依赖&#xff0c;仅仅通过几条简单命令行就完成配置的操作感到惊叹&#xff0c;非常的省事省力。反倒是C/C开发时&#xff0c;要是每个库都要自己下载源码编译或者对环境进行配置…

【Docker】常用帮忙、镜像、容器、其他命令合集(2)

【Docker】常用帮忙、镜像、容器、其他命令合集&#xff08;2&#xff09;博主有话说容器命令新建容器并启动列出所有的运行的容器退出容器docker run -it centos:7.0.1406 /bin/bash指令解析docker exec -it ... bash 、docker run -it ... bash、docker attach [容器] 的exit…

系统编程.9 线程

1.线程概述程序运行起来编程进程&#xff0c;进程由一个个线程构成。eg&#xff1a;没有启动的qq时一个程序&#xff0c;启动后登录qq&#xff0c;qq是一个进程&#xff0c;实际上进程什么都没做&#xff0c;只是提供了需要的资源&#xff0c;打开聊天框可以和别人进行通信&…

2.10组件间的通信

1.Vue组件的嵌套关系1.1认识组件的嵌套前面我们是将所有的逻辑放到一个 App.vue 中&#xff1b;在之前的案例中&#xff0c;我们只是创建了一个组件 App&#xff1b;如果我们一个应用程序所有的逻辑都放在一个组件中&#xff0c;那么这个组件就会变成非常的臃肿和难以维护&…

Mybatis-Plus学习笔记

目录 一、MyBatis-Plus简介 二、MyBatisPlus使用的基本流程&#xff1a; &#xff08;1&#xff09;引入MybatisPlus依赖&#xff0c;代替MyBatis依赖 &#xff08;2&#xff09;自定义Mapper继承BaseMapper ​编辑&#xff08;3&#xff09;在实体类上添加注解声明表信息…