精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

福利视频一区二区| 国产精品1区2区3区| 亚洲欧美日韩精品| 日本三级黄色网址| 岛国成人毛片| 波多野结衣中文字幕一区二区三区 | 蜜桃精品久久久久久久免费影院| 俄罗斯毛片基地| 亚洲精品一区av| 激情成人中文字幕| 亚洲图片小说在线| 欧美一级一区二区三区| 老司机精品视频网站| 久热精品视频在线观看| aaaaa级少妇高潮大片免费看| 在线中文字幕-区二区三区四区| 老妇喷水一区二区三区| 久久精品久久久久电影| 日本一卡二卡在线| 日韩黄色在线| 91久久奴性调教| 99在线免费视频观看| 成人免费一区二区三区视频网站| 久久久久久网| 欧美精品成人91久久久久久久| 在线观看av免费观看| 黄色18在线观看| 亚洲欧美一区二区三区孕妇| 日韩高清在线播放| 天堂中文资源在线观看| 国产乱国产乱300精品| 国产精品扒开腿爽爽爽视频 | 免费国产成人av| 欧美另类tv| 国产精品嫩草影院com| 久久精品日产第一区二区三区精品版| 日韩网红少妇无码视频香港| 青青草国产免费一区二区下载| 在线中文字幕一区| 日韩一级性生活片| 福利视频在线| 亚洲私人影院在线观看| 亚洲高清123| 黄色毛片在线看| 91麻豆精品一区二区三区| 99热在线播放| 国产成人精品一区二三区四区五区 | 国产情侣在线视频| 欧美99在线视频观看| 中文字幕不卡av| 精品人妻无码一区| 深爱激情久久| 亚洲欧洲美洲在线综合| 爱爱免费小视频| 一区二区美女| 国产亚洲精品一区二555| 中文字幕免费看| 精品国产乱码久久久久久1区2匹| 欧美日韩aaaaaa| 婷婷激情四射五月天| 影音成人av| 欧美在线观看18| 亚洲成人天堂网| 欧美天堂一区| 777xxx欧美| 国产精品久久久久久9999| 亚洲精品无播放器在线播放| 欧美一区二区在线看| 在线视频日韩欧美| 欧美a在线观看| 欧美精品一区视频| 亚洲av成人精品一区二区三区| 成人黄色免费观看| 欧美日韩国产影片| 永久av免费在线观看| 亚洲1区在线| 日韩精品免费电影| 1024手机在线观看你懂的| 日韩精品欧美| 色综合久久88| 中文字幕一区二区三区手机版| 99久久精品费精品国产风间由美| 日韩福利视频在线观看| 国产aⅴ激情无码久久久无码| av在线亚洲色图| 亚洲精品国产成人| 成人小视频免费看| 欧美国产三区| 97av视频在线| 日韩黄色片网站| 国产一区二区精品在线观看| 精品九九九九| 91大神xh98hx在线播放| 一区二区三区在线看| 久久国产精品视频在线观看| 性欧美gay| 日韩一区二区免费高清| 久久久无码人妻精品一区| 色综合狠狠操| 97碰在线观看| 国产一区二区女内射| www.性欧美| 亚洲一区美女| 麻豆理论在线观看| 欧美精品aⅴ在线视频| 97精品人妻一区二区三区蜜桃| 7m精品国产导航在线| 亚洲欧美在线看| 日本中文字幕免费在线观看| 日韩精品欧美精品| 成人黄色片视频网站| 国产视频精品久久| 亚洲午夜在线电影| 国产探花在线看| 亚洲另类av| 欧美人与物videos| 亚洲天堂aaa| 91天堂素人约啪| 国产精品国三级国产av| 国产精品.xx视频.xxtv| 精品中文字幕久久久久久| 亚洲国产精品免费在线观看| 奇米色一区二区| 激情小说网站亚洲综合网 | 中文字幕av一区二区| 欧美重口另类videos人妖| 在线播放av网址| 日韩欧美不卡| 2024亚洲男人天堂| 亚洲国产www| 亚洲视频图片小说| 国产精品拍拍拍| 亚洲精品播放| 欧美在线欧美在线| 欧性猛交ⅹxxx乱大交| 亚洲欧美一区二区在线观看| wwwwww.色| 国产精品一国产精品| 97国产一区二区精品久久呦| 国产成人精品白浆久久69| 亚洲欧洲av一区二区三区久久| 亚洲精品日韩在线观看| 国产美女高潮在线| 欧美mv日韩mv国产网站app| 极品色av影院| 卡一卡二国产精品| 亚洲一区二区三区午夜| 国产精品久久久久久妇女| 亚洲日韩欧美视频| www.久久久久久久| 久久男人中文字幕资源站| 99爱视频在线| 久久综合色占| 国产精品白嫩初高中害羞小美女| 国产伦精品一区二区三区免.费| 成人精品高清在线| 妞干网在线播放| 成功精品影院| 91国内产香蕉| 青青草在线视频免费观看| 欧美性猛交xxxxx水多| 在线免费看黄视频| 日韩国产成人精品| 亚洲在线不卡| 老司机亚洲精品一区二区| 欧美成人精品三级在线观看| 99久久精品国产一区色| 亚洲综合图片区| 欧美一级片黄色| 久久综合影音| 国产91av视频在线观看| 精品伊人久久| 97视频在线观看免费高清完整版在线观看 | 色乱码一区二区三区网站| 国产精品网站大全| 午夜视频在线观看网站| 91精品欧美综合在线观看最新 | 亚洲视频小说图片| 无码人妻少妇色欲av一区二区| 精品九九在线| 亚洲最大福利视频| 国产乱妇乱子在线播视频播放网站| 欧美区视频在线观看| 青青草原免费观看| 成人av网在线| 麻豆三级在线观看| 欧美午夜国产| 欧美极品视频一区二区三区| 黄色欧美视频| 国内精品美女av在线播放| 天堂在线免费av| 欧美日韩国产精品自在自线| 国产一级做a爰片在线看免费| 韩国av一区二区三区四区| 美女扒开大腿让男人桶| 国产一区二区三区91| 91麻豆国产精品| 国产无遮挡裸体视频在线观看| 日韩三级免费观看| av黄色在线看| 亚洲视频一区在线| 国产一卡二卡三卡四卡| 丝袜诱惑制服诱惑色一区在线观看 | 熟妇人妻系列aⅴ无码专区友真希| 亚洲男人的天堂在线aⅴ视频 | 欧美一级网址| 98精品在线视频| 五月香视频在线观看| 亚洲韩国日本中文字幕| 中文文字幕一区二区三三| 亚洲午夜久久久久中文字幕久| 精品国产乱码久久久久夜深人妻| 欧美+亚洲+精品+三区| 日韩精品欧美在线| 免费萌白酱国产一区二区三区| 97国产suv精品一区二区62| 亚乱亚乱亚洲乱妇| 精品视频久久久久久| 国产成人免费看一级大黄| 色婷婷av久久久久久久| 国产一级aa大片毛片| 国产精品久久三| 国产传媒第一页| 成人免费视频免费观看| 99国产精品久久久久久| 日韩电影在线一区二区三区| 精品这里只有精品| 国产综合精品| 日韩a级黄色片| 小小影院久久| 亚洲在线不卡| 色综合久久网| 一区二区三区国产福利| 欧美限制电影| 特级西西444www大精品视频| 网曝91综合精品门事件在线| 国产精品免费视频一区二区| 综合伊人久久| a级国产乱理论片在线观看99| 在线观看v片| 2024亚洲男人天堂| 91探花在线观看| 久久久久亚洲精品| 五月天激情在线| 色综合色综合久久综合频道88| 欧美成人免费| 亚洲欧美日韩中文在线| 亚洲 国产 欧美 日韩| 亚洲国产精品网站| 日韩永久免费视频| 亚洲第一页在线| 亚洲欧美日韩精品永久在线| 精品国产伦一区二区三区免费| 自拍偷拍精品视频| 欧美无砖专区一中文字| 中文字幕一区二区在线视频| 欧美在线观看18| 97超碰国产在线| 欧美一区二区视频观看视频| www.久久成人| 欧美精品一区二区在线播放| 日韩porn| 色婷婷**av毛片一区| 暖暖日本在线观看| 欧美区在线播放| 女厕盗摄一区二区三区| 日本国产高清不卡| 91p九色成人| 91亚洲精品久久久久久久久久久久| 三上悠亚一区二区| 国产精品中文在线| 久久丁香四色| 精品一区二区三区自拍图片区| 99久久999| 粉嫩av四季av绯色av第一区| 日本欧美三级| 亚洲日本一区二区三区在线不卡| 天天躁日日躁成人字幕aⅴ| 免费成人看片网址| 欧洲杯足球赛直播| 性欧美大战久久久久久久免费观看| 亚洲欧洲av| 亚洲国产精品久久久久婷婷老年 | 91免费观看视频在线| 国产精品20p| 亚洲乱码中文字幕| 日韩欧美亚洲一区二区三区| 在线观看av一区二区| 99re只有精品| 亚洲午夜精品久久久久久性色| 猫咪在线永久网站| 美日韩在线视频| 亚洲淫成人影院| 亚洲自拍高清视频网站| 欧美人与动xxxxz0oz| 在线免费观看成人网| 国产精品久久久久久久久久妞妞 | 深夜福利影院在线观看| 黑人巨大精品欧美一区二区免费| 国产精品第二十页| 精品视频在线免费看| 日本高清视频www| 中文字幕亚洲在线| 欧美xxxhd| 91久久久久久久一区二区| 综合亚洲自拍| 日本精品福利视频| 蜜臀国产一区二区三区在线播放 | 国产免费观看高清视频| 久久成人免费日本黄色| 泷泽萝拉在线播放| 亚洲黄色在线视频| 中文字幕一区二区人妻| 亚洲福利视频免费观看| 黄色av网站在线播放| 国产成人精品a视频一区www| 国产一区二区三区不卡av| 一区二区精品在线观看| 日韩av在线发布| 人妻丰满熟妇aⅴ无码| 一区二区三区成人| 一区二区三区午夜| 国产亚洲精品久久久优势 | 中文字幕色av一区二区三区| 国产精品suv一区| 亚洲国产精品嫩草影院久久| 97超碰在线公开在线看免费| 国产日本欧美一区| 精品久久久久中文字幕小说| 欧美日韩在线中文| 豆国产96在线|亚洲| 欧美黄色aaa| 日韩欧美国产综合| 黄色免费在线观看| 国产精品日韩久久久久| 欧美日韩在线二区| 欧美丰满熟妇xxxxx| 久久久影视传媒| 国产亚洲欧美在线精品| 日韩精品在线视频美女| 日韩伦理精品| 免费看成人片| 视频一区在线播放| 国产免费无遮挡吸奶头视频| 一本到不卡免费一区二区| 亚洲 精品 综合 精品 自拍| 欧美性在线视频| 九九热线有精品视频99| 日韩中文字幕免费在线| 国产日产亚洲精品系列| 波多野结衣电车| 上原亚衣av一区二区三区| 欧美xxxx网站| 日韩不卡一二区| 丁香婷婷综合五月| 麻豆一区二区三区精品视频| 亚洲成人av资源网| 国产夫妻在线| 日本欧美精品久久久| 青青草成人在线观看| 萌白酱视频在线| 日韩视频123| 无码小电影在线观看网站免费| 91九色国产在线| 午夜精品偷拍| 亚洲天堂资源在线| 91传媒视频在线播放| 亚乱亚乱亚洲乱妇| 999在线观看免费大全电视剧| 成人嫩草影院| 久久精品一卡二卡| 悠悠色在线精品| 视频一区二区三区在线看免费看| 久久资源免费视频| 97久久亚洲| 欧美在线观看www| 国产精品日产欧美久久久久| 亚洲AV无码精品自拍| 51色欧美片视频在线观看| 日韩成人精品一区| 男人操女人下面视频| 精品福利视频导航| 无遮挡动作视频在线观看免费入口| 国产精品对白刺激| 偷偷www综合久久久久久久| 黄色av电影网站| 欧美调教femdomvk| 日本片在线看| 日韩高清国产一区在线观看| 国产99久久精品| 久久精品视频5| 欧美另类老女人| 国产一区网站| 91传媒理伦片在线观看| 欧美影院一区二区| av在线加勒比| 综合久久国产| 国产视频一区二区在线| 午夜精品一区二区三| 国产精品久久久久9999|