第四章 第四节 per_cpu
我們上一章說了
實現內核同步的方法很多,如下表
技術 | 說明 | 適用范圍 |
每CPU變量 | 在CPU之間復制數據結構 | 所有CPU |
原子操作 | 對一個計數器原子地“讀-修改-寫”的指令 | 所有CPU |
內存屏障 | 避免指令重新排序 | 本地CPU或所有CPU |
自旋鎖 | 加鎖時忙等 | 所有CPU |
信號量 | 加鎖時阻塞等待 | 所有CPU |
順序鎖 | 基于訪問計數器的鎖 | 所有CPU |
本地中斷的禁止 | 禁止單個CPU上的中斷處理 | 本地CPU |
本地軟中斷的禁止 | 禁止單個CPU上的可延遲函數處理 | 本地CPU |
讀-復制-更新(RCU) | 通過指針而不是鎖來訪問共享數據結構 | 所有CPU |
但是這個每CPU變量,讓我看起來非常的拗口,什么是每CPU變量,我剛開始看的時候,以為別人寫錯了,后面又查了很多資料,確定是對的,才放心,原來是翻譯的問題
優點
per_cpu的好處是訪問它不需要加鎖,而且這個變量存在CPU的cache里,訪問速度會非???/strong>
原英文是 per_cpu
/* * Add a offset to a pointer but keep the pointer as is. * * Only S390 provides its own means of moving the pointer. */ #ifndef SHIFT_PERCPU_PTR /* Weird cast keeps both GCC and sparse happy. */ #define SHIFT_PERCPU_PTR(__p, __offset) ({ \ __verify_pcpu_ptr((__p)); \ RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \ }) #endif /* * A percpu variable may point to a discarded regions. The following are * established ways to produce a usable pointer from the percpu variable * offset. */ #define per_cpu(var, cpu) \ (*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu))) |
既然這么拗口,我覺得就沒有必要翻譯了,直接說明是per_cpu 就好了
怎么使用這個 per_cpu 呢?
在源碼
drivers\cpufreq\cpufreq_userspace.c
下面有一個使用的歷程
聲明一個 per_cpu
static DEFINE_PER_CPU(unsigned int, cpu_is_managed); #define DEFINE_PER_CPU(type, name) \ DEFINE_PER_CPU_SECTION(type, name, "") |
使用一個per_cpu
get_cpu_var(var) 和 set_cpu_var(var) |
使用另一個CPU的per_cpu變量
per_cpu(cpu_cur_freq, freq->cpu) = freq->new; |
導出一個per_cpu 變量供其他模塊使用
EXPORT_PER_CPU_SYMBOL(per_cpu_var); EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var); |
注意!!
在使用per_cpu的時候,記得禁止內核搶占
DECLARE_PER_CPU(int, mycounter); ● int cpu; ● preempt_disable(); //禁止搶占 ● cpu = smp_processor_id(); ● per_cpu(mycounter, cpu) += 1; ● preempt_enable(); //開啟內核搶占 |
SMP系統chcae 命中
什么是smp 系統呢?就是有幾個 CPU組成的芯片,就是我們通常說的幾核幾核的說法,大概的圖像這樣
? ? ? ? ? ? ? ? ? ? ? ?
per_cpu解決的是多個CPU上共享數據的問題,如果聲明了一個變量A,這個變量A在每個CPU下都有自己的副本,使用的堆棧地址也不一樣,但是如果改變了A的值,其他的CPU同樣能獲取這個改變的值。
這樣的話每個CPU只要關心單個CPU的并發問題,不用考慮多CPU的互斥加鎖并發問題。
聲明和定義Per-CPU變量的API | 描述 |
DECLARE_PER_CPU(type, name)? DEFINE_PER_CPU(type, name) | 普通的、沒有特殊要求的per cpu變量定義接口函數。沒有對齊的要求 |
DECLARE_PER_CPU_FIRST(type, name)? DEFINE_PER_CPU_FIRST(type, name) | 通過該API定義的per cpu變量位于整個per cpu相關section的最前面。 |
DECLARE_PER_CPU_SHARED_ALIGNED(type, name)? DEFINE_PER_CPU_SHARED_ALIGNED(type, name) | 通過該API定義的per cpu變量在SMP的情況下會對齊到L1 cache line ,對于UP,不需要對齊到cachine line |
DECLARE_PER_CPU_ALIGNED(type, name)? DEFINE_PER_CPU_ALIGNED(type, name) | 無論SMP或者UP,都是需要對齊到L1 cache line |
DECLARE_PER_CPU_PAGE_ALIGNED(type, name)? DEFINE_PER_CPU_PAGE_ALIGNED(type, name) | 為定義page aligned per cpu變量而設定的API接口 |
DECLARE_PER_CPU_READ_MOSTLY(type, name)? DEFINE_PER_CPU_READ_MOSTLY(type, name) | 通過該API定義的per cpu變量是read mostly |
per_cpu 在內存中固定的section
? ? ? ? ? ? ? ? ? ? ? ?
參考資料:(公眾號后臺回復 per_cpu ?獲取)
? ? ? ? ? ? ? ? ? ? ? ?
推薦閱讀:
第4章 第三節 內核同步
第4章 原子操作 第二節
總結
以上是生活随笔為你收集整理的第四章 第四节 per_cpu的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Scikit Learn的分类器探索
- 下一篇: pdfminer将pdf转为csv