Linux kernel 为什么Linux内核使用循环双链表来存储进程列表?
Linux内核将进程列表存储在循环双链接列表中,称为任务列表。背后的原因是什么?为什么使用循环双链接列表?使用此数据结构的优点是什么?创建者试图通过使用此数据结构实现什么?灵活性,因此,如果您知道例如您正在搜索的内容可能已经过时,您可以使用Linux kernel 为什么Linux内核使用循环双链表来存储进程列表?,linux-kernel,process-management,Linux Kernel,Process Management,Linux内核将进程列表存储在循环双链接列表中,称为任务列表。背后的原因是什么?为什么使用循环双链接列表?使用此数据结构的优点是什么?创建者试图通过使用此数据结构实现什么?灵活性,因此,如果您知道例如您正在搜索的内容可能已经过时,您可以使用列表\u for\u each\u entry\u reverse宏,而不是通常的正向宏 “在遍历整个列表时使用链表非常重要,并且需要动态添加和删除元素…使用这种类型的链表提供了最大的灵活性” 而且没有代码重复 “在过去,内核中有多个链表实现。需要一个强大的链
列表\u for\u each\u entry\u reverse
宏,而不是通常的正向宏
“在遍历整个列表时使用链表非常重要,并且需要动态添加和删除元素…使用这种类型的链表提供了最大的灵活性”
而且没有代码重复
“在过去,内核中有多个链表实现。需要一个强大的链表实现来删除重复代码。在2.1内核开发系列中,引入了官方的内核链表实现。”
资料来源:罗伯特·洛夫。“Linux内核开发”(第三版)。p、 87-94在大多数情况下,根本不使用任务列表。内核通过线程信息结构中的指针(并通过堆栈指针到达后者)或通过当前任务的全局指针(ahem)到达任务结构 只有在需要遍历任务列表时(由于任务列表的长度可变,因此这是一种罕见且固有的低效操作,因此在大型计算机上它可以增长到数十万甚至数百万个条目),才会使用链表。在这种情况下,可以方便地从列表中的任何一点开始,然后继续,直到回到开始的位置(即循环列表)。为什么它是双重链接的,我不确定,但我想链接只会在一个已经很大的结构上增加几个字节,而且以任何一种方式遍历它的灵活性都是值得的。
编辑:事实上,正如@thrig在另一个答案中指出的,原因是内核中有一个人人都使用的链表实现(没有奇怪的错误,因为有人使用了自己的),而这恰好是一个双链表实现,正是因为它的一些用户需要灵活性。以某种形式列出对象(如进程)的原因是,有时内核需要枚举所有这些对象,即依次遍历每个对象。这意味着必须有一种方法来查找此类型的所有对象。如果可以一次创建和删除一个对象,那么链表是最简单的解决方案 列表需要双重链接才能支持删除对象。删除对象时,代码需要更新指向该对象的所有指针。因此,对象需要包含一个指向指向它的所有其他对象的指针(或者至少需要有一个从对象本身开始的指针链)。对于单链表,从a中删除B→B→C、 除了遍历所有对象直到找到正确的对象,没有办法发现需要更新其指针的对象。使用双链接列表,从a中删除B↔B↔C、 将指针从B指向A,并将A指向B的指针改为指向C,同样地,C也是如此。As, 有时内核需要循环所有进程 (例如,在处理
kill(-1,sig)
时,
它向每个进程发送sig
呼叫进程有权发送信号,
过程1除外-请参阅)
我已经很久没有看这个代码了;
但是,在Unix的早期版本中,进程表是一个数组-
一些固定数量的连续proc
结构
(有时称为“进程槽”)。例如,
“查看所有流程”循环可能看起来像这样:
for (i = 0; i < PROC_MAX; i++) // This would probably really have started with i = 1
{ // so as not to look at proc[0], i.e., PID 1.
if (proc[i].flags & IS_AN_ACTIVE_PROCESS)
do something with the process
}
对于(i=0;iPROC\u MAX
(可能有数千个)
处理插槽只是为了找到其中包含实际进程的插槽-
可能是一个小得多的数字
将流程放入链接列表中
允许内核对每个进程执行某些操作
无需搜索一个空洞的过程表
此外,如果所有内容都与链表联系在一起,
拥有一个动态调整大小的流程表是可行的
如果/当初始默认静态进程表已满,
只需分配更多(非连续)内存并将它们链接在一起
附言。 我相信可能有多个流程列表:
- 一个整体,
- 一个用于可运行(处于“运行”状态)的进程
- 一个用于当前实际运行的进程 在(至少)一个处理器上
- 一个用于等待事件的进程 (例如,完成I/O请求)
- 等等
查找等待tty输入的进程。因此,您的第一段说,如果您知道您感兴趣的进程,您不需要使用进程列表来访问它。 比如说,如果一个朋友告诉你他的电话号码,你不需要在电话簿上查他就可以给他打电话。 这对我来说似乎微不足道。 我是否遗漏了更深层次的含义?@G-Man:关键是,与数组相比,迭代链表的速度较慢,因此重要的是,大多数任务的访问都不是通过此数据结构进行的。负载