精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Linux內核里的“智能指針”

系統 Linux 開源
C/C++語言本身并不支持垃圾回收機制,雖然語言本身具有極高的靈活性,但是當遇到大型的項目時,繁瑣的內存管理往往讓人痛苦異常。Linux內核是如何解決這個問題呢?同樣作為C語言的解決方案,Linux內核采用的也是引用計數的方式。

眾所周知,C/C++語言本身并不支持垃圾回收機制,雖然語言本身具有極高的靈活性,但是當遇到大型的項目時,繁瑣的內存管理往往讓人痛苦異?!,F代的C/C++類庫一般會提供智能指針來作為內存管理的折衷方案,比如STL的auto_ptr,Boost的Smart_ptr庫,QT的QPointer家族,甚至是基于C語言構建的GTK+也通過引用計數來實現類似的功能。Linux內核是如何解決這個問題呢?同樣作為C語言的解決方案,Linux內核采用的也是引用計數的方式。如果您更熟悉C++,可以把它類比為Boost的shared_ptr,或者是QT的QSharedPointer。

在Linux內核里,引用計數是通過 struct kref 結構來實現的。在介紹如何使用 kref 之前,我們先來假設一個情景。假如您開發的是一個字符設備驅動,當設備插上時,系統自動建立一個設備節點,用戶通過文件操作來訪問設備節點。

如上圖所示,最左邊的綠色框圖表示實際設備的插拔動作,中間黃色的框圖表示內核中設備對象的生存周期,右邊藍色的框圖表示用戶程序系統調用的順序。如果用戶程序正在訪問的時候設備突然被拔掉,驅動程序里的設備對象是否立刻釋放呢?如果立刻釋放,用戶程序執行的系統調用一定會發生內存非法訪問;如果要等到用戶 程序close之后再釋放設備對象,我們應該怎么來實現?kref就是為了解決類似的問題而生的。

kref的定義非常簡單,其結構體里只有一個原子變量。

  1. struct kref { 
  2.  atomic_t refcount; 
  3. }; 

Linux內核定義了下面三個函數接口來使用kref:

  1. void kref_init(struct kref *kref); 
  2. void kref_get(struct kref *kref); 
  3. int kref_put(struct kref *kref, void (*release) (struct kref *kref)); 

我們先通過一段偽代碼來了解一下如何使用kref。

  1. struct my_obj 
  2.  int val; 
  3.  struct kref refcnt; 
  4. }; 
  5.   
  6. struct my_obj *obj; 
  7.   
  8. void obj_release(struct kref *ref)  
  9.  struct my_obj *obj = container_of(ref, struct my_obj, refcnt); 
  10.  kfree(obj); 
  11.   
  12. device_probe()  
  13.  obj = kmalloc(sizeof(*obj), GFP_KERNEL); 
  14.  kref_init(&obj->refcnt); 
  15.   
  16. device_disconnect()  
  17.  kref_put(&obj->refcnt, obj_release); 
  18.   
  19. .open()  
  20.  kref_get(&obj->refcnt); 
  21.   
  22. .close()  
  23.  kref_put(&obj->refcnt, obj_release); 

在這段代碼里,我們定義了obj_release來作為釋放設備對象的函數,當引用計數為0時,這個函數會被立刻調用來執行真正的釋放動作。我們先在 device_probe里把引用計數初始化為1,當用戶程序調用open時,引用計數又會被加1,之后如果設備被拔 掉,device_disconnect會減掉一個計數,但此時refcnt還不是0,設備對象obj并不會被釋放,只有當close被調用之 后,obj_release才會執行。

看完偽代碼之后,我們再來實戰一下。為了節省篇幅,這個實作并沒有建立一個字符設備,只是通過模塊的加載和卸載過程來對感受一下kref。

  1. #include <linux/kernel.h> 
  2. #include <linux/module.h> 
  3.   
  4. struct my_obj { 
  5.  int val; 
  6.  struct kref refcnt; 
  7. }; 
  8.   
  9. struct my_obj *obj; 
  10.   
  11. void obj_release(struct kref *ref) 
  12.  struct my_obj *obj = container_of(ref, struct my_obj, refcnt); 
  13.  printk(KERN_INFO "obj_release\n"); 
  14.  kfree(obj); 
  15.   
  16. static int __init kreftest_init(void) 
  17.  printk(KERN_INFO "kreftest_init\n"); 
  18.  obj = kmalloc(sizeof(*obj), GFP_KERNEL); 
  19.  kref_init(&obj->refcnt); 
  20.  return 0; 
  21.   
  22. static void __exit kreftest_exit(void) 
  23.  printk(KERN_INFO "kreftest_exit\n"); 
  24.  kref_put(&obj->refcnt, obj_release); 
  25.  return
  26.   
  27. module_init(kreftest_init); 
  28. module_exit(kreftest_exit); 
  29.   
  30. MODULE_LICENSE("GPL"); 

#p#

通過kbuild編譯之后我們得到kref_test.ko,然后我們順序執行以下命令來掛載和卸載模塊。

sudo insmod ./kref_test.ko

sudo rmmod kref_test

此時,系統日志會打印出如下消息:

kreftest_init

kreftest_exit

obj_release

這正是我們預期的結果。

有了kref引用計數,即使內核驅動寫的再復雜,我們對內存管理也應該有信心了吧!

接下來主要介紹幾點使用kref時的注意事項。

Linux內核文檔kref.txt羅列了三條規則,我們在使用kref時必須遵守。

規則一:

If you make a non-temporary copy of a pointer, especially if it can be passed to another thread of execution, you must increment the refcount with kref_get() before passing it off;

規則二:

When you are done with a pointer, you must call kref_put();

規則三:

If the code attempts to gain a reference to a kref-ed structure without already holding a valid pointer, it must serialize access where a kref_put() cannot occur during the kref_get(), and the structure must remain valid during the kref_get().

對于規則一,其實主要是針對多條執行路徑(比如另起一個線程)的情況。如果是在單一的執行路徑里,比如把指針傳遞給一個函數,是不需要使用kref_get的??聪旅孢@個例子:

  1. kref_init(&obj->ref); 
  2.   
  3. // do something here 
  4. // ... 
  5.   
  6. kref_get(&obj->ref); 
  7. call_something(obj); 
  8. kref_put(&obj->ref); 
  9.   
  10. // do something here 
  11. // ... 
  12.   
  13. kref_put(&obj->ref); 

您是不是覺得call_something前后的一對kref_get和kref_put很多余呢?obj并沒有逃出我們的掌控,所以它們確實是沒有必要的。

但是當遇到多條執行路徑的情況就完全不一樣了,我們必須遵守規則一。下面是摘自內核文檔里的一個例子:

  1. struct my_data 
  2.  . 
  3.  . 
  4.  struct kref refcount; 
  5.  . 
  6.  . 
  7. }; 
  8.   
  9. void data_release(struct kref *ref) 
  10.  struct my_data *data = container_of(ref, struct my_data, refcount); 
  11.  kfree(data); 
  12.   
  13. void more_data_handling(void *cb_data) 
  14.  struct my_data *data = cb_data; 
  15.  . 
  16.  . do stuff with data here 
  17.  . 
  18.  kref_put(&data->refcount, data_release); 
  19.   
  20. int my_data_handler(void) 
  21.  int rv = 0; 
  22.  struct my_data *data; 
  23.  struct task_struct *task; 
  24.  data = kmalloc(sizeof(*data), GFP_KERNEL); 
  25.  if (!data) 
  26.  return -ENOMEM; 
  27.  kref_init(&data->refcount); 
  28.   
  29.  kref_get(&data->refcount); 
  30.  task = kthread_run(more_data_handling, data, "more_data_handling"); 
  31.  if (task == ERR_PTR(-ENOMEM)) { 
  32.  rv = -ENOMEM; 
  33.  goto out
  34.  } 
  35.   
  36.  . 
  37.  . do stuff with data here 
  38.  . 
  39.  out
  40.  kref_put(&data->refcount, data_release); 
  41.  return rv; 

因為我們并不知道線程more_data_handling何時結束,所以要用kref_get來保護我們的數據。

注意規則一里的那個單詞“before”,kref_get必須是在傳遞指針之前進行,在本例里就是在調用kthread_run之前就要執行kref_get,否則,何談保護呢?

對于規則二我們就不必多說了,前面調用了kref_get,自然要配對使用kref_put。

規則三主要是處理遇到鏈表的情況。我們假設一個情景,如果有一個鏈表擺在你的面前,鏈表里的節點是用引用計數保護的,那你如何操作呢?首先我們需要獲得節點的指針,然后才可能調用kref_get來增加該節點的引用計數。根據規則三,這種情況下我們要對上述的兩個動作串行化處理,一般我們可以用mutex來實現。請看下面這個例子:

  1. static DEFINE_MUTEX(mutex); 
  2. static LIST_HEAD(q); 
  3. struct my_data 
  4.  struct kref refcount; 
  5.  struct list_head link; 
  6. }; 
  7.   
  8. static struct my_data *get_entry() 
  9.  struct my_data *entry = NULL
  10.  mutex_lock(&mutex); 
  11.  if (!list_empty(&q)) { 
  12.  entry = container_of(q.next, struct my_q_entry, link); 
  13.  kref_get(&entry->refcount); 
  14.  } 
  15.  mutex_unlock(&mutex); 
  16.  return entry; 
  17.   
  18. static void release_entry(struct kref *ref) 
  19.  struct my_data *entry = container_of(ref, struct my_data, refcount); 
  20.   
  21.  list_del(&entry->link); 
  22.  kfree(entry); 
  23.   
  24. static void put_entry(struct my_data *entry) 
  25.  mutex_lock(&mutex); 
  26.  kref_put(&entry->refcount, release_entry); 
  27.  mutex_unlock(&mutex); 

這個例子里已經用mutex來進行保護了,假如我們把mutex拿掉,會出現什么情況?記住,我們遇到的很可能是多線程操作。如果線程A在用 container_of取得entry指針之后、調用kref_get之前,被線程B搶先執行,而線程B碰巧又做的是kref_put的操作,當線程A恢復執行時一定會出現內存訪問的錯誤,所以,遇到這種情況一定要串行化處理。

我們在使用kref的時候要嚴格遵循這三條規則,才能安全有效的管理數據。

責任編輯:火鳳凰 來源: wwang博客
相關推薦

2021-08-11 09:01:48

智能指針Box

2010-12-17 10:07:59

2010-01-27 14:18:41

Android智能指針

2010-02-05 14:36:20

C++智能指針

2021-07-30 05:12:54

智能指針C++編程語言

2017-04-12 14:30:45

Linux內核DebugFS

2023-11-17 11:48:08

智能指針C++

2011-07-01 14:28:47

Qt 指針

2021-09-09 17:05:36

C++智能指針語言

2024-12-26 10:45:08

2023-12-20 12:40:51

C++RAII編程

2024-03-01 16:43:48

C++11智能指針內存

2025-08-01 01:55:00

2021-07-29 06:09:05

萬能指針C語言void

2025-06-17 08:10:00

智能指針C++代碼

2022-02-08 09:09:45

智能指針C++

2024-01-24 11:44:44

C++智能指針開發

2025-02-26 01:23:02

C++11Raw代碼

2016-08-24 20:09:27

Linux數據結構位數組

2020-11-11 14:48:41

Linux內核代碼
點贊
收藏

51CTO技術棧公眾號

久久免费小视频| 国产成人精品视频ⅴa片软件竹菊| 中文字幕观看在线| 午夜国产一区二区| 欧美日韩一区二区在线视频| 亚洲狠狠婷婷综合久久久| 久久精品久久久久久久| 欧美日韩一区二区三区视频播放| 欧美日韩免费在线视频| 成人短视频在线观看免费| 国产成人自拍一区| 日韩精品一级中文字幕精品视频免费观看 | 激情五月色综合国产精品| 欧洲色大大久久| 色乱码一区二区三区熟女| 成人免费视频国产| 日韩精品亚洲专区| 久久视频这里只有精品| 国模无码视频一区| 成人国产精品入口免费视频| 一区二区三区高清不卡| 欧美三日本三级少妇三99| 中文字幕在线观看视频一区| 激情成人综合| 亚洲男人天堂视频| 中日韩av在线播放| sm捆绑调教国产免费网站在线观看| 2020国产精品| 69堂成人精品视频免费| 亚洲va在线观看| 欧美女激情福利| 中文字幕欧美国内| 国产女人18毛片水真多18| 人人玩人人添人人澡欧美| 午夜国产精品一区| 五月天综合网| 亚洲AV第二区国产精品| 国产精选一区二区三区| 国产大片精品免费永久看nba| 久久久精品视频免费观看| 亚洲欧美校园春色| 日韩欧美不卡一区| 天天爽人人爽夜夜爽| h片在线观看视频免费| 亚洲色图视频免费播放| 日韩高清av电影| 日本激情一区二区| 国产黄人亚洲片| 国产欧洲精品视频| 免费的毛片视频| 日韩视频一区| 欧美黑人一区二区三区| 成年人二级毛片| 99久久精品费精品国产| 国产一区二区三区在线视频| 99久久人妻无码中文字幕系列| 亚洲一区二区三区在线免费| 欧美精品在线视频| 无码人妻精品一区二区三区66| 欧美1234区| 玉足女爽爽91| 国产精品久久久影院| 日本在线免费| 国产精品网站在线| 精品视频高清无人区区二区三区| www.天天干.com| 久久成人精品无人区| 欧美亚洲第一区| 亚洲久久在线观看| 在线亚洲观看| 国内精品美女av在线播放| 精品爆乳一区二区三区无码av| 一区二区三区四区在线观看国产日韩| 日韩在线视频免费观看| 一二三四在线观看视频| 色爱综合网欧美| 亚洲欧美日韩国产精品| 少妇按摩一区二区三区| 香蕉久久夜色精品国产使用方法 | 私库av在线播放| 天天射—综合中文网| 久久成年人视频| 麻豆changesxxx国产| 午夜精品视频| 久久免费福利视频| 国产精品视频免费播放| 久久久久久一区二区| 国产精品国产三级国产专播精品人| 人人草在线观看| 日韩av不卡一区二区| 国产在线一区二区三区| 国产又粗又猛又爽又黄视频| 麻豆精品一区二区综合av| 亚洲一区精品电影| 日韩av资源站| 亚洲人成小说网站色在线| 蜜桃传媒一区二区三区| 精品美女一区| 日韩大陆毛片av| 疯狂撞击丝袜人妻| 国产亚洲欧洲| 1卡2卡3卡精品视频| 同心难改在线观看| 亚洲黄色片在线观看| 麻豆av免费在线| 亚洲经典视频| 宅男66日本亚洲欧美视频| 精品无码av在线| 久久99久久精品| 精品一区二区三区免费毛片| 哥也色在线视频| 91黄视频在线观看| 亚洲啪av永久无码精品放毛片| 欧美国产一级| 国产ts一区二区| 蜜臀久久精品久久久久| 亚洲欧洲精品天堂一级| 成人三级视频在线播放| 日韩一区二区三区精品| 日韩亚洲欧美成人| 亚洲成熟少妇视频在线观看| 97久久人人超碰| 日本中文字幕一级片| 久久亚洲精品人成综合网| 亚洲精品影视在线观看| 日韩美女视频网站| 国产成人av福利| 2021狠狠干| 亚洲伦理一区二区| 国产亚洲欧美视频| 六月丁香婷婷综合| av中文字幕不卡| 亚洲理论电影在线观看| 欧美片网站免费| 久久天天躁夜夜躁狠狠躁2022| 做爰视频毛片视频| 久久久精品欧美丰满| 国产资源在线视频| 欧美电影免费网站| 午夜伦理精品一区| 熟妇高潮一区二区高潮| 午夜电影网亚洲视频| 国产女主播在线播放| 国产精品s色| yellow视频在线观看一区二区| av文字幕在线观看| 欧美放荡的少妇| 免费国产羞羞网站美图| 国产伦精品一区二区三区免费迷| 裸体大乳女做爰69| 欧美经典一区| 高清欧美电影在线| 午夜福利理论片在线观看| 精品美女永久免费视频| 黄色性生活一级片| 美女尤物久久精品| 日韩精品久久久毛片一区二区| 日本综合字幕| 在线看福利67194| 一级片视频播放| 亚洲激情在线播放| 中文字幕在线视频播放| 久久xxxx| 亚洲第一页在线视频| 蜜桃精品视频| 97视频在线看| av在线二区| 欧美一区二区三区在线视频| 青娱乐91视频| 99r精品视频| 亚洲黄色a v| 一本一本久久a久久综合精品| 99久久精品无码一区二区毛片 | 人人爽香蕉精品| 中文字幕在线亚洲三区| 亚洲一区二区电影| 日本高清+成人网在线观看| 成人高潮成人免费观看| 91麻豆精品国产自产在线观看一区| 久久久久久久久久久97| 91蜜桃在线观看| 嫩草视频免费在线观看| 亚洲美女啪啪| 一区二区三区四区欧美| 嗯用力啊快一点好舒服小柔久久| 国产98色在线| 午夜激情在线| 亚洲欧美中文另类| 国产黄频在线观看| 91激情在线视频| 久久国产精品二区| 国产欧美一区二区精品久导航| 4438x全国最大成人| 久久九九99| 麻豆视频传媒入口| 国产一区二区三区探花| 国产精品区一区二区三在线播放| 欧亚一区二区| 欧美精品www在线观看| yw193.com尤物在线| 日韩欧美中文字幕制服| 国产又大又粗又爽| 亚洲一区二区四区蜜桃| 国产精品综合激情| 波多野结衣视频一区| 日本一二区免费| 久久午夜精品| 性高湖久久久久久久久aaaaa| 成人同人动漫免费观看 | 亚洲欧洲日本精品| 亚洲全部视频| 欧美少妇在线观看| 日本一二区不卡| 精品欧美一区二区久久久伦| 精品亚洲二区| 国产日韩欧美在线看| 日韩电影av| 91禁外国网站| 波多野结衣在线观看| 久久电影一区二区| 91网在线播放| 国产亚洲欧美一区| 黄色av网站在线| 亚洲精品电影网在线观看| 99久久精品无免国产免费 | 中文字幕 日韩 欧美| 久久婷婷影院| 国产无套内射久久久国产| 在线观看日韩av电影| 欧美这里只有精品| 综合激情一区| 玖玖精品在线视频| 亚洲国产老妈| 9色视频在线观看| 亚州av乱码久久精品蜜桃| 亚洲精品一品区二品区三品区 | 国产一区二区免费| 日色在线视频| 亚洲欧美国产日韩天堂区| 午夜小视频免费| 亚洲美女视频网| 青青草观看免费视频在线| 日韩精品在线播放| 天堂av中文在线资源库| 亚洲男人的天堂网站| 黄色电影免费在线看| 亚洲天堂av女优| a黄色在线观看| 中文字幕在线日韩| 老司机在线永久免费观看| 久久精品影视伊人网| 欧美性videos| 欧美日韩999| free性护士videos欧美| 国产91精品久久久久久| 韩国美女久久| 国产精品免费观看在线| 欧美激情不卡| 99视频网站| 久久久久观看| 欧美一级爱爱| 99久久精品费精品国产风间由美| 欧美 国产 精品| 一区二区国产精品| 欧美一级片中文字幕| 美女视频网站久久| 日批视频在线看| 不卡一区二区在线| 无码一区二区三区在线| 亚洲同性同志一二三专区| 久久精品波多野结衣| 精品人伦一区二区三区蜜桃免费| 成人午夜精品视频| 91精品国产欧美一区二区| 天堂国产一区二区三区| 伊人久久男人天堂| 一区二区三区伦理| 欧美亚洲另类在线| 日韩成人一区| 国内一区在线| 久久精品国产亚洲夜色av网站| 国产精品自拍合集| 日韩精品国产精品| 无码人妻aⅴ一区二区三区玉蒲团| 91免费国产在线观看| 国产精品国产三级国产传播| 欧美日韩国产综合视频在线观看中文| 日韩不卡高清视频| 精品人在线二区三区| 黑人与亚洲人色ⅹvideos| 欧美日韩成人黄色| 久久野战av| 国产精品久久精品视| 欧美精品羞羞答答| 日韩中文字幕在线免费| 麻豆精品一区二区综合av| 这里只有精品在线观看视频| 国产精品美女久久久久高潮| 国产乡下妇女做爰视频| 欧美色图在线观看| 神马午夜在线观看| 久久影视电视剧免费网站清宫辞电视 | 欧美日韩导航| 麻豆视频传媒入口| 蜜桃精品视频在线| 亚洲永久无码7777kkk| 亚洲美女在线国产| 自拍偷拍精品视频| 日韩精品中文在线观看| 综合久久2o19| 国产精品亚洲美女av网站| 三级精品视频| 777av视频| 国产毛片精品国产一区二区三区| 日本一级免费视频| 黄色成人av网| 亚洲风情第一页| 久久网福利资源网站| 素人一区二区三区| 免费亚洲一区二区| 亚洲国产黄色| 久久久男人的天堂| 亚洲免费观看视频| 国产精品久久久久久久成人午夜| 伊人成人开心激情综合网| 亚洲欧美se| 精品伊人久久大线蕉色首页| 影音国产精品| 妖精视频一区二区| 亚洲国产裸拍裸体视频在线观看乱了| 国产丝袜在线视频| 久久久999精品| 91丨精品丨国产| 裸体大乳女做爰69| 国产一区三区三区| 国产67194| 欧美一区二区三区四区久久| 黄网站免费在线观看| 91免费福利视频| 久久精品国内一区二区三区水蜜桃| 亚洲一级片网站| 中文av字幕一区| 国产精品久久婷婷| 操91在线视频| 6080成人| 免费看又黄又无码的网站| 99精品久久久久久| 欧美特黄aaaaaa| 亚洲欧美制服第一页| 国产一区一一区高清不卡| 天堂va久久久噜噜噜久久va| 蜜臀av性久久久久蜜臀aⅴ| 99热在线观看精品| 91精品欧美一区二区三区综合在| 99福利在线| 国产伦精品一区二区三区视频黑人 | 日韩在线观看av| 日本精品一区二区三区在线观看视频| 日韩成人午夜影院| 成人丝袜高跟foot| 特级毛片www| 色播久久人人爽人人爽人人片视av| 日本精品久久| 福利视频一区二区三区四区| 91丨porny丨蝌蚪视频| 波多野结衣一区二区三区四区| 色偷偷噜噜噜亚洲男人的天堂| 日韩视频在线直播| 各处沟厕大尺度偷拍女厕嘘嘘| 欧美高清在线一区| 国产欧美日韩综合精品一区二区三区 | 精品无人区无码乱码毛片国产| 欧美性一区二区| 99视频免费在线观看| 精品一区二区不卡| 六月丁香综合在线视频| 久久国产一级片| 亚洲欧美激情视频| 精品国产一区二| 人妻少妇被粗大爽9797pw| 国产精品乱码人人做人人爱 | 日韩欧美一级大片| 久久视频在线播放| 偷拍自拍亚洲色图| 五月天婷婷在线观看视频| 天天色综合成人网| 亚洲欧美视频一区二区| 国产精品区一区| 蜜桃视频一区二区| 日本少妇性高潮| 视频一区视频二区国产精品| 成人福利免费在线观看| 在线观看免费成人av| 亚洲成人av在线电影| 午夜免费福利在线观看| 久久精品magnetxturnbtih| 久久99国产精品免费网站| 国产精品777777| 欧美巨乳美女视频| 精品精品久久|