By: fulinux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎点赞和订阅!
你的喜欢就是我写作的动力!
目录
- 1. DEFINE_PER_CPU和DECLARE_PER_CPU
- 1. 1. DEFINE_PER_CPU
- 1.2. DECLARE_PER_CPU
- 2. 区别
- 2.1. 定义与声明:
- 2.2. 使用场景:
- 2.3. 编译器处理:
- 3. 使用方法
- 4.示例使用 my_counter
- 5. 总结
参考:Linux内核机制—percpu
1. DEFINE_PER_CPU和DECLARE_PER_CPU
DEFINE_PER_CPU 和 DECLARE_PER_CPU 是 Linux 内核中用于声明和定义 per-CPU 变量的宏。这些宏允许内核在每个 CPU 上拥有独立的变量副本,这对于多处理器系统上的并发编程非常有用,可以避免锁的竞争。
1. 1. DEFINE_PER_CPU
DEFINE_PER_CPU 宏用于定义一个 per-CPU 变量。它通常在内核模块的源代码文件中使用,直接定义一个全局变量。使用DEFINE_PER_CPU 宏定义的变量会被放置在特定的内存区域,每个 CPU 都有自己的副本。
语法:
DEFINE_PER_CPU(type, name);
- type: 变量的数据类型。
- name: 变量的名称。
1.2. DECLARE_PER_CPU
DECLARE_PER_CPU 宏用于声明一个 per-CPU 变量。它通常在头文件中使用,用来声明一个 per-CPU 变量,而实际的定义则需要在某个源文件中通过 DEFINE_PER_CPU 来完成。
DECLARE_PER_CPU(type, name);
- type: 变量的数据类型。
- name: 变量的名称。
2. 区别
2.1. 定义与声明:
- DEFINE_PER_CPU 既定义了变量,也声明了它。这意味着你可以在源文件中直接使用 DEFINE_PER_CPU 来创建一个 per-CPU 变量。
- DECLARE_PER_CPU 只声明变量,实际的定义需要在其他地方使用 DEFINE_PER_CPU 来完成。
2.2. 使用场景:
- DEFINE_PER_CPU 通常用于源文件中,直接定义 per-CPU 变量。
- DECLARE_PER_CPU 通常用于头文件中,提供外部接口访问 per-CPU 变量。
2.3. 编译器处理:
- DEFINE_PER_CPU 会直接在源文件中创建变量的定义。
- DECLARE_PER_CPU 则只在头文件中声明变量的存在,不会创建实际的变量定义。
3. 使用方法
假设我们有一个 per-CPU 变量 my_counter,我们可以这样声明和定义它:
//per_cpu.h
#ifndef PER_CPU_H
#define PER_CPU_H
DECLARE_PER_CPU(int, my_counter);
#endif /* PER_CPU_H */
//源文件per_cpu.c
#include "per_cpu.h"
DEFINE_PER_CPU(int, my_counter);
一旦 my_counter 被声明和定义,你就可以在内核模块或其他源文件中使用它。可以通过 __get_cpu_var 或 __this_cpu_read 宏来读取当前 CPU 的副本,通过 __set_cpu_var 或 __this_cpu_write 来修改当前 CPU 的副本。
读取 my_counter
int current_cpu_counter = __this_cpu_read(my_counter);
或者
int cpu_id = smp_processor_id();
int counter_value = __get_cpu_var(my_counter)[cpu_id];
修改 my_counter
__this_cpu_write(my_counter, value);
或者:
int cpu_id = smp_processor_id();
__set_cpu_var(my_counter)[cpu_id] = value;
4.示例使用 my_counter
假设你想要在一个内核模块中初始化 my_counter 并在每个 CPU 上递增它。
内核模块 (my_module.c)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include "per_cpu.h"
static int __init my_module_init(void)
{
int cpu;
for_each_online_cpu(cpu) {
__set_cpu_var(my_counter)[cpu] = 0; // 初始化每个 CPU 的 my_counter
}
printk(KERN_INFO "Module initialized.\n");
return 0;
}
static void __exit my_module_exit(void)
{
printk(KERN_INFO "Module removed.\n");
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
增加计数器的函数 (increment_counter.c)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include "per_cpu.h"
void increment_my_counter(void)
{
int cpu_id = smp_processor_id();
int current_value = __get_cpu_var(my_counter)[cpu_id];
__set_cpu_var(my_counter)[cpu_id] = current_value + 1;
}
5. 总结
- 使用 __this_cpu_read 和 __this_cpu_write 来读取和修改当前 CPU 的副本。
- 使用 __get_cpu_var 和 __set_cpu_var 来访问特定 CPU 的副本。
这样,你就可以在内核模块中使用 my_counter 这个 per-CPU 变量了。如果你有其他具体的需求或问题,请随时告诉我。