03 Linux内核中几个重要内核数据结构构

linux内核链表:深入分析 Linux 内核链表的数据结构 | 网站架构
linux内核链表:深入分析 Linux 内核链表的数据结构
  一、 链表数据结构简介  链表是一种常用的组织有序数据的数据结构,它通过指针将一系列数据节点连接成一条数据链,是线性表的一种重要实现方式。相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入或删除数据。链表的开销主要是访问的顺序性和组织链的空间损失。    通常链表数据结构至少应包含两个域:数据域和指针域,数据域用于数据,指针域用于建立与下一个节点的联系。按照指针域的组织以及各个节点之间的联系形式,链表又可以分为单链表、双链表、循环链表等多种类型,下面分别给出这几类常见链表类型的示意图:    1. 单链表    图1 单链表     单链表是最简单的一类链表,它的特点是仅有一个指针域指向后继节点(next),因此,对单链表的遍历只能从头至尾(通常是NULL空指针)顺序进行。    2. 双链表    图2 双链表     通过设计前驱和后继两个指针域,双链表可以从两个方向遍历,这是它区别于单链表的地方。如果打乱前驱、后继的依赖关系,就可以构成"二叉树";如果再让首节点的前驱指向链表尾节点、尾节点的后继指向首节点(如图2中虚线部分),就构成了循环链表;如果设计更多的指针域,就可以构成各种复杂的树状数据结构。    3. 循环链表  循环链表的特点是尾节点的后继指向首节点。前面已经给出了双循环链表的示意图,它的特点是从任意一个节点出发,沿两个方向的任何一个,都能找到链表中的任意一个数据。如果去掉前驱指针,就是单循环链表。    在Linux内核中使用了大量的链表结构来组织数据,包括设备列表以及各种功能模块中的数据组织。这些链表大多采用在[include//list.h]实现的一个相当精彩的链表数据结构。本文的后继部分就将通过示例详细介绍这一数据结构的组织和使用。    二、 Linux 2.6内核链表数据结构的实现  尽管这里使用2.6内核作为讲解的基础,但实际上2.4内核中的链表结构和2.6并没有什么区别。不同之处在于2.6扩充了两种链表数据结构:链表的读拷贝更新(rcu)和HASH链表(hlist)。这两种扩展都是基于最基本的list结构,因此,本文主要介绍基本链表结构,然后再简要介绍一下rcu和hlist。    链表数据结构的定义很简单(节选自[include//list.h],以下所有代码,除非加以说明,其余均取自该文件):    struct list_head {   struct list_head *next, *  };    list_head结构包含两个指向list_head结构的指针prev和next,由此可见,内核的链表具备双链表功能,实际上,通常它都组织成双循环链表。    和第一节介绍的双链表结构模型不同,这里的list_head没有数据域。在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点。    在数据结构课本中,链表的经典定义方式通常是这样的(以单链表为例):    struct list_node {   struct list_node *   ElemType   };    因为ElemType的缘故,对每一种数据项类型都需要定义各自的链表结构。有经验的C++程序员应该知道,标准模板库中的采用的是C++ Template,利用模板抽象出和数据项类型无关的链表操作接口。    在Linux内核链表中,需要用链表组织起来的数据通常会包含一个struct list_head成员,例如在[include/linux/netfilter.h]中定义了一个nf_sockopt_ops结构来描述Netfilter为某一族准备的getsockopt/setsockopt接口,其中就有一个(struct list_head list)成员,各个族的nf_sockopt_ops结构都通过这个list成员组织在一个链表中,表头是定义在[net/core/netfilter.c]中的nf_sockopts(struct list_head)。从下图中我们可以看到,这种通用的链表结构避免了为每个数据项类型定义自己的链表的麻烦。Linux的简捷实用、不求完美和标准的风格,在这里体现得相当充分。    图3 nf_sockopts链表示意图     三、 链表操作接口  1. 声明和初始化  实际上Linux只定义了链表节点,并没有专门定义链表头,那么一个链表结构是如何建立起来的呢?让我们来看看LIST_HEAD()这个宏:    #define LIST_HEAD_INIT(name) { &(name), &(name) }  #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)    当我们用LIST_HEAD(nf_sockopts)声明一个名为nf_sockopts的链表头时,它的next、prev指针都初始化为指向自己,这样,我们就有了一个空链表,因为Linux用头指针的next是否指向自己来判断链表是否为空:    static inline int list_empty(const struct list_head *head)  {  
return head->next ==  }    除了用LIST_HEAD()宏在声明的时候初始化一个链表以外,Linux还提供了一个INIT_LIST_HEAD宏用于运行时初始化链表:    #define INIT_LIST_HEAD(ptr) do {
(ptr)->next = (ptr); (ptr)->prev = (ptr); } while (0)    我们用INIT_LIST_HEAD(&_sockopts)来使用它。    2. 插入/删除/合并  a) 插入    对链表的插入操作有两种:在表头插入和在表尾插入。Linux为此提供了两个接口:    static inline void list_add(struct list_head *new, struct list_head *head);  static inline void list_add_tail(struct list_head *new, struct list_head *head);    因为Linux链表是循环表,且表头的next、prev分别指向链表中的第一个和最末一个节点,所以,list_add和list_add_tail的区别并不大,实际上,Linux分别用    __list_add(new, head, head->next);    和    __list_add(new, head->prev, head);    来实现两个接口,可见,在表头插入是插入在head之后,而在表尾插入是插入在head->prev之后。    假设有一个新nf_sockopt_ops结构变量new_sockopt需要添加到nf_sockopts链表头,我们应当这样操作:    list_add(&_sockopt.list, &_sockopts);    从这里我们看出,nf_sockopts链表中记录的并不是new_sockopt的地址,而是其中的list元素的地址。如何通过链表访问到new_sockopt呢?下面会有详细介绍。    b) 删除    static inline void list_del(struct list_head *entry);    当我们需要删除nf_sockopts链表中添加的new_sockopt项时,我们这么操作:    list_del(&_sockopt.list);    被剔除下来的new_sockopt.list,prev、next指针分别被设为LIST_POSITION2和LIST_POSITION1两个特殊值,这样设置是为了保证不在链表中的节点项不可访问--对LIST_POSITION1和LIST_POSITION2的访问都将引起页故障。与之相对应,list_del_init()函数将节点从链表中解下来之后,调用LIST_INIT_HEAD()将节点置为空链状态。    c) 搬移    Linux提供了将原本属于一个链表的节点移动到另一个链表的操作,并根据插入到新链表的位置分为两类:    static inline void list_move(struct list_head *list, struct list_head *head);  static inline void list_move_tail(struct list_head *list, struct list_head *head);    例如list_move(&_sockopt.list,&_sockopts)会把new_sockopt从它所在的链表上删除,并将其再链入nf_sockopts的表头。    d) 合并    除了针对节点的插入、删除操作,Linux链表还提供了整个链表的插入功能:    static inline void list_splice(struct list_head *list, struct list_head *head);    假设当前有两个链表,表头分别是list1和list2(都是struct list_head变量),当调用list_splice(&list1;,&list2;)时,只要list1非空,list1链表的内容将被挂接在list2链表上,位于list2和list2.next(原list2表的第一个节点)之间。新list2链表将以原list1表的第一个节点为首节点,而尾节点不变。如图(虚箭头为next指针):    图4 链表合并list_splice(&list1;,&list2;)     当list1被挂接到list2之后,作为原表头指针的list1的next、prev仍然指向原来的节点,为了避免引起混乱,Linux提供了一个list_splice_init()函数:     static inline void list_splice_init(struct list_head *list, struct list_head *head);     该函数在将list合并到head链表的基础上,调用INIT_LIST_HEAD(list)将list设置为空链。    3. 遍历  遍历是链表最经常的操作之一,为了方便核心应用遍历链表,Linux链表将遍历操作抽象成几个宏。在介绍遍历宏之前,我们先看看如何从链表中访问到我们真正需要的数据项。    a) 由链表节点到数据项变量    我们知道,Linux链表中仅保存了数据项结构中list_head成员变量的地址,那么我们如何通过这个list_head成员访问到作为它的所有者的节点数据呢?Linux为此提供了一个list_entry(ptr,type,member)&>&深入理解linux内核(第二版)中文版
深入理解linux内核(第二版)中文版
上传大小:38.45MB
《深入理解Linux内核,第二版》指导你对内核中使用的最重要的数据结构、算法和程序设计诀窍进行一次遍历。通过对表面特性的探究,作者给那些想知道自己机器工作原理的人提供了颇有价值的见解。书中讨论了Intel特有的重要性质。相关的代码片段被逐行剖析。然而,本书涵盖的不仅仅是代码的功能,它解释了Linux以自己的方式工作的理论基础。
综合评分:5
{%username%}回复{%com_username%}{%time%}\
/*点击出现回复框*/
$(".respond_btn").on("click", function (e) {
$(this).parents(".rightLi").children(".respond_box").show();
e.stopPropagation();
$(".cancel_res").on("click", function (e) {
$(this).parents(".res_b").siblings(".res_area").val("");
$(this).parents(".respond_box").hide();
e.stopPropagation();
/*删除评论*/
$(".del_comment_c").on("click", function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_invalid/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parents(".conLi").remove();
alert(data.msg);
$(".res_btn").click(function (e) {
var parentWrap = $(this).parents(".respond_box"),
q = parentWrap.find(".form1").serializeArray(),
resStr = $.trim(parentWrap.find(".res_area_r").val());
console.log(q);
//var res_area_r = $.trim($(".res_area_r").val());
if (resStr == '') {
$(".res_text").css({color: "red"});
$.post("/index.php/comment/do_comment_reply/", q,
function (data) {
if (data.succ == 1) {
var $target,
evt = e || window.
$target = $(evt.target || evt.srcElement);
var $dd = $target.parents('dd');
var $wrapReply = $dd.find('.respond_box');
console.log($wrapReply);
//var mess = $(".res_area_r").val();
var mess = resS
var str = str.replace(/{%header%}/g, data.header)
.replace(/{%href%}/g, 'http://' + window.location.host + '/user/' + data.username)
.replace(/{%username%}/g, data.username)
.replace(/{%com_username%}/g, data.com_username)
.replace(/{%time%}/g, data.time)
.replace(/{%id%}/g, data.id)
.replace(/{%mess%}/g, mess);
$dd.after(str);
$(".respond_box").hide();
$(".res_area_r").val("");
$(".res_area").val("");
$wrapReply.hide();
alert(data.msg);
}, "json");
/*删除回复*/
$(".rightLi").on("click", '.del_comment_r', function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_comment_del/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parent().parent().parent().parent().parent().remove();
$(e.target).parents('.res_list').remove()
alert(data.msg);
//填充回复
function KeyP(v) {
var parentWrap = $(v).parents(".respond_box");
parentWrap.find(".res_area_r").val($.trim(parentWrap.find(".res_area").val()));
评论共有2条
不错,清晰的书,可以读
还可以,蛮清晰的
VIP会员动态
热门资源标签
CSDN下载频道资源及相关规则调整公告V11.10
下载频道用户反馈专区
下载频道积分规则调整V1710.18
spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip
资源所需积分/C币
当前拥有积分
当前拥有C币
输入下载码
为了良好体验,不建议使用迅雷下载
深入理解linux内核(第二版)中文版
会员到期时间:
剩余下载个数:
剩余积分:0
为了良好体验,不建议使用迅雷下载
积分不足!
资源所需积分/C币
当前拥有积分
您可以选择
程序员的必选
绿色安全资源
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
无法举报自己的资源
你当前的下载分为234。
你还不是VIP会员
开通VIP会员权限,免积分下载
你下载资源过于频繁,请输入验证码
您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:!
若举报审核通过,可返还被扣除的积分
被举报人:
请选择类型
资源无法下载 ( 404页面、下载失败、资源本身问题)
资源无法使用 (文件损坏、内容缺失、题文不符)
侵犯版权资源 (侵犯公司或个人版权)
虚假资源 (恶意欺诈、刷分资源)
含色情、危害国家安全内容
含广告、木马病毒资源
*投诉人姓名:
*投诉人联系方式:
*版权证明:
*详细原因:
深入理解linux内核(第二版)中文版搜索关键字:linux内核数据结构
17个结果)
1、前言 最近项目中用到一个环形缓冲区(ring buffer),代码是由linux内核的kfifo改过来的。缓冲区在文件系统中经常用到,通过缓冲区缓解cpu读写内存和读写磁盘的速度。例如一个进程A产生数据发给另外一个进程B,进程B需要对进程A传的数据进行处理并写入文件,如果B没有处理完,则A要延迟 ...
分类:&&&时间: 13:18:51&&&
阅读次数:77
1、前言 最近写代码需用到链表结构,正好公共库有关于链表的。第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域。后来看代码注释发现该代码来自linux内核,在linux源代码下include/Lish.h下。这个链表具备通用性,使用非常方便。只需要在结构定义一个 ...
分类:&&&时间: 13:18:09&&&
阅读次数:60
与经典双向链表比较 经典双向链表如图。其中有一个pre指针和一个next指针,数据是在链表的节点内。 内核链表如图。每一个链表节点内只有一个pre指针和一个next指针,整个链表节点嵌入到了一个需要使用链表的结构体内。 内核链表介绍 内核链表节点结构体定义如图。其中next指针指向下一个链表节点,p ...
分类:&&&时间: 20:57:28&&&
阅读次数:109
1 #include 2 #include 3 4 #define MAX_PRIO 10000 5 #define BITS_PER_LONG 32 6 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 7 8 #define BIT(nr) (1... ...
分类:&&&时间: 14:37:57&&&
阅读次数:147
Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到。我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为广泛的数据结构,具体你可以 查看 这里。 首先让我们看一下主要的结构体: struct list_h ...
分类:&&&时间: 19:23:50&&&
阅读次数:195
Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到。我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为广泛的数据结构,具体你可以 查看 这里。首先让我们看一下主要的结构体: struct list_he ...
分类:&&&时间: 19:13:38&&&
阅读次数:128
Linux内核数据结构之链表
分类:&&&时间: 14:34:18&&&
阅读次数:133
首先我先回顾一下二叉树
然后回顾一下二叉搜索树
下面是重头戏
自平衡二叉搜索树满足二叉搜索树的条件。即每个节点左边的节点值都要比自己小,然后满足平衡,即树(包括子树)的末尾节点深度相差小于1,这样的树称为平衡二叉搜索树
最后红黑树...
分类:&&&时间: 22:16:28&&&
阅读次数:88
1、前言 最近写代码需用到链表结构,正好公共库有关于链表的。第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域。后来看代码注释发现该代码来自linux内核,在linux源代码下include/Lish.h下。这个链表具备通用性,使用非常方便。只需要在结构定义一个 ...
分类:&&&时间: 21:52:52&&&
阅读次数:57
之所以要写本文,主要是当我看到Linux内核中链表的设计,让我叹为观止。Linux实现的方式与众不同,它不是将数据结构塞入链表中,而是将链表节点塞入数据结构中。在Linux源码中,链表在头文件中声明。它的节点的原型如下:struct list_head{ struct list_he...
分类:&&&时间: 18:15:40&&&
阅读次数:94
&&国之画&&&& &&&&chrome插件
版权所有 京ICP备号-2
迷上了代码!Linux 内核数据结构:Radix 树_教育指南_百度教育攻略
正如你所知道的, Linux 内核通过许多不同库以及函数提供各种数据结构以及算法。这个部分我们将介绍其中一个数据结构Radix tree。Linux 内核中有两个文件与&code&radix tree&/code&的实现和 API 相关:include/linux/radix-tree.hlib/radix-tree.c首先说明一下什么是&code&radix tree&/code&,Radix tree 是一个&code&压缩 trie&/code&,trie是一种通过保存关联数组(associative array)来提供&code&关键字-值(key-value)&/code&存储与查找的数据结构。通常关键字是字符串,不过也可以是其他数据类型。 Trie 结构的节点与&code&n-tree&/code&不同,其节点中并不存储关键字,取而代之的是存储单个字符标签。关键字查找时,通过从树的根开始遍历关键字相关的所有字符标签节点,直至到达最终的叶子节点。下面是个例子:精彩内容,尽在百度攻略:http://gl.baidu.com这个例子中,我们可以看到 trie 所存储的关键字信息&code&go&/code&与&code&cat&/code&,压缩 trie 或&code&radix tree&/code&与&code&trie&/code&所不同的是,对于只有一个孩子的中间节点将被压缩。Linux 内核中的 Radix 树将值映射为整型关键字,Radix 的数据结构定义在include/linux/radix-tree.h文件中 :上面这个是 radix 树的 root 节点的结构体,它包括三个成员:精彩内容,尽在百度攻略:http://gl.baidu.com&code&height&/code&:从叶节点向上计算出的树高度。&code&gfp_mask&/code&:内存申请的标识。&code&rnode&/code&:子节点指针。这里首先要讨论的结构体成员是&code&gfp_mask&/code&:Linux 底层的内存申请接口需要提供一类标识(flag) –&code&gfp_mask&/code&,用于描述内存申请的行为。这个以&code&GFP_&/code&前缀开头的内存申请控制标识主要包括,&code&GFP_NOIO&/code&禁止所有 IO 操作但允许睡眠等待内存,&code&__GFP_HIGHMEM&/code&允许申请内核的高端内存,&code&GFP_ATOMIC&/code&高优先级申请内存且操作不允许被睡眠。精彩内容,尽在百度攻略:http://gl.baidu.com接下来说的节结构体成员是&code&rnode&/code&:这个结构体中包括这几个内容,节点与父节点的偏移以及到树底端的高度、子节点的个数、节点的存储数据域,具体描述如下:&code&path&/code&:与父节点的偏移以及到树底端的高度&code&count&/code&:子节点的个数。&code&parent&/code&:父节点的指针。&code&private_data&/code&:存储数据内容缓冲区。&code&rcu_head&/code&:用于节点释放的 RCU 链表。&code&private_list&/code&– 存储数据。精彩内容,尽在百度攻略:http://gl.baidu.com结构体&code&radix_tree_node&/code&的最后两个成员&code&tags&/code&与&code&slots&/code&是非常重要且需要特别注意的。每个 Radix 树节点都可以包括一个指向存储数据指针的 slots 集合,空闲 slots 的指针指向 NULL。 Linux 内核的 Radix 树结构体中还包含用于记录节点存储状态的标签&code&tags&/code&成员,标签通过位设置指示 Radix 树的数据存储状态。至此,我们了解到 radix 树的结构,接下来看一下 radix 树所提供的 API。Linux 内核 radix 树 API精彩内容,尽在百度攻略:http://gl.baidu.com我们从数据结构的初始化开始看,radix 树支持两种方式初始化。第一个是使用宏&code&RADIX_TREE&/code&:正如你看到,只需要提供&code&name&/code&参数,就能够使用&code&RADIX_TREE&/code&宏完成 radix 的定义以及初始化,&code&RADIX_TREE&/code&宏的实现非常简单:精彩内容,尽在百度攻略:http://gl.baidu.com&code&RADIX_TREE&/code&宏首先使用&code&name&/code&定义了一个&code&radix_tree_root&/code&实例,并用&code&RADIX_TREE_INIT&/code&宏带参数&code&mask&/code&进行初始化。宏&code&RADIX_TREE_INIT&/code&将&code&radix_tree_root&/code&初始化为默认属性,并将 gfp_mask 初始化为入参&code&mask&/code&。第二种方式是手工定义&code&radix_tree_root&/code&变量,之后再使用&code&mask&/code&调用&code&INIT_RADIX_TREE&/code&宏对变量进行初始化。&code&INIT_RADIX_TREE&/code&宏定义:精彩内容,尽在百度攻略:http://gl.baidu.com宏&code&INIT_RADIX_TREE&/code&所初始化的属性与&code&RADIX_TREE_INIT&/code&一致接下来是 radix 树的节点插入以及删除,这两个函数:&code&radix_tree_insert&/code&;&code&radix_tree_delete&/code&.精彩内容,尽在百度攻略:http://gl.baidu.com第一个函数&code&radix_tree_insert&/code&需要三个入参:radix 树 root 节点结构索引关键字需要插入存储的数据第二个函数&code&radix_tree_delete&/code&除了不需要存储数据参数外,其他与&code&radix_tree_insert&/code&一致。精彩内容,尽在百度攻略:http://gl.baidu.comradix 树的查找实现有以下几个函数:&code&radix_tree_lookup&/code&;&code&radix_tree_gang_lookup&/code&;&code&radix_tree_lookup_slot&/code&;第一个函数&code&radix_tree_lookup&/code&需要两个参数:精彩内容,尽在百度攻略:http://gl.baidu.comradix 树 root 节点结构索引关键字这个函数通过给定的关键字查找 radix 树,并返关键字所对应的结点。第二个函数&code&radix_tree_gang_lookup&/code&具有以下特征:精彩内容,尽在百度攻略:http://gl.baidu.com函数返回查找到记录的条目数,并根据关键字进行排序,返回的总结点数不超过入参&code&max_items&/code&的大小。最后一个函数&code&radix_tree_lookup_slot&/code&返回结点 slot 中所存储的数据。链接精彩内容,尽在百度攻略:http://gl.baidu.comRadix treeTrie23814 条评论分享收藏感谢收起kernel.org全部作了镜像()。网站宗旨:收集Linux从酝酿到开发初始版本有关的所有资料和信息(); 重新建立起最古老的Linux可运行系统,这些系统在其它地方很难再找到了; 为初学者提供一个学习Linux内核基本工作原理的最简单方法。本书新版:《Linux内核完全剖析--基于0.12内核》2009年出的,很厚。===============自制操作系统系列================== 9.《Orange S:一个操作系统的实现》作者:于渊出版社: 电子工业出版社; 第1版 (日)本书第一版2005年出版,这是第二版。从只有二十行的引导扇区代码出发,一步一步地向读者呈现一个操作系统框架的完成过程。10.《30天自制操作系统》 作者: (日)川合秀实
[作译者介绍] 译者: 周自恒 李黎明 曾祥江 张文旭 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:0点评:小日本写的,不过确实写的内容很好,讲怎么自己一步步写操作系统,从汇编到C都有涉及。 _________________________________________________________________________unix是Linux的基础,学习linux也要看unix Unix的绝版好书UNIX操作系统设计原书名:The Design of the UNIX Operating System 作者: (美)Maurice J.Bach
译者: 陈葆钰 王旭 柳纯录 冯雪山 丛书名: 计算机科学丛书 出版社:机械工业出版社 ISBN:1点评:当年linux之父参考过,非常经典,无需多言---------------------------------------------------------- UNIX编程环境原书名:The UNIX Programming Environment作者: Brianw.Kernighan
译者: 陈向群 丛书名: 计算机科学丛书 出版社:机械工业出版社 点评:非常好的入门书.书中绝无生僻的角落,对于入门来说没有什么难以理解的。但是字里行间浸透了作者设计unix的指导思想,这一点是别的入门书无法企及的。 书中提及的点滴都是实用的方法和准则,而这些充斥着在unix上一整天的工作,即使是有经验的用户学过此书后工作效率也会提升。UNIX高级教程系统技术内幕作者: (美)Uresh Vahalia
译者: 聊鸿斌/等
出版社: 清华大学出版社 出版年: 1999-05 点评:老书,有电子版。linux/unix的顶级宝贝!补充:评论区知友
推荐一本《 操作系统真象还原 》作者:郑刚出版社: 人民邮电出版社 出版年:2016-03点评: 用诙谐幽默语言讲述的深入理解操作系统原理的精品 轻松自制操作系统 操作系统并不深奥 本书给予全新解读 你想更深入了解学习Linux知识体系,你可以看一下我们花费了一个多月整理了上百小时的几百个知识点体系内容: 赞同 854 条评论分享收藏感谢收起}

我要回帖

更多关于 Linux内核常用数据结构 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信