关于在linux container_of宏观疑虑 [英] Doubts regarding container_of macro in linux

查看:256
本文介绍了关于在linux container_of宏观疑虑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么我们使用 container_of 宏?

container_of(pointer, container_type, container_field);

它是在LDD说

这个宏接受一个指向名为 container_field ,内场
  键入 CONTAINER_TYPE 的结构,并返回一个指针
  包含结构。

"This macro takes a pointer to a field named container_field, within a structure of type container_type, and returns a pointer to the containing structure".

我的问题是:


  • 如果我们希望有一个指针结构(即CONTAINER_TYPE)我们可以
    直接分配,对吧?

  • 那么,为什么它的领域之一,在拍摄的指针分配
    解决整个结构?

  • 任何人可以请用一个例子说明了使用的好处
    该宏?

推荐答案

我给大家举一个例子:

struct A
{
    int some_data;
    int other_data;
};

现在让我们说有这个功能:

Now let's say there is this function:

int get_some_data_from_other(int *other)
{
    struct A *a = container_of(other, struct A, other_data);
    return a->some_data;
}

正如你所看到的,我们可以告诉什么是原始的结构A 包含给定为int *其他,通过了解该指针理应指向该结构的字段。 这里的关键是,我们的的具有对结构本身的引用,而只是一个指针,其成员之一

As you can see, we are able to tell what is the original struct A that contains the given int *other, by knowing which field of the struct that pointer supposedly points to. The key here is that we don't have a reference to the struct itself, but just a pointer to one of its members.

这看似荒谬,但实际上是一些非常聪明的结构非常有用。一个非常常见的例子是内核创建链表的方式。我建议你​​阅读这个职位上kernelnewbies.org 。让我们来看看它的一个简单的例子:

This may seem absurd, but is actually useful in some very clever constructs. One very common example is the way the kernel creates linked lists. I suggest you read this post on kernelnewbies.org. Let's see a short example of it:

struct whatever
{
    /* whatever data */
    struct list_head mylist;
};

所以结构的任何有一些数据,但它也希望作为一个链表内的节点。他们教你在学校什么是有不同的结构,包含接下来 / $ P $光伏指针作为还有一个指向结构无论(或无效* )。这样的话,你必须通过它,你得到你的数据节点。

So struct whatever has some data, but it also wants to act as a node inside a linked list. What they teach you in school is to have a different struct, that contains the next/prev pointers as well as a pointer to struct whatever (or void *). That way, you have nodes through which you get to your data.

这是所有软件工程标准,这实际上是一件好事。但是软件工程标准有w.r.t效率一点问候。请参见为什么我已经用C写Ze​​roMQ,而不是C ++(第二部分)

By all software engineering standards, that's actually a good thing. But software engineering standards have little regards w.r.t efficiency. See Why should I have written ZeroMQ in C, not C++ (part II).

底线是,与传统的方法,你必须从数据节点分别分配链表节点,即你双倍的内存分配,回收,破碎和他人之间高速缓存未命中的开销。 Linux内核做它的方式是相反的。每个数据节点包含一个通用链表节点。通用链表节点不知道有关数据任何东西,或他们是如何分配的,只有知道如何连接到其它链接列表节点。

Bottom line is, with the conventional method, you have to allocate the linked list node separately from the data node, i.e. you double the overhead of memory allocation, deallocation, fragmentation and cache misses among others. The way the Linux kernel does it is the opposite. Each data node contains a generic linked list node. The generic linked list node does not know anything about the data or how they were allocated and knows only how to connect to other linked list nodes.

让我们来深入了解一下:

So let's take a deeper look:

 +-------------------+      +---------------------+      +---------------------+
 |                   |      |                     |      |                     |
 |   WHATEVER DATA   |      |   WHATEVER DATA 2   |      |   WHATEVER DATA 3   |
 |                   |      |                     |      |                     |
 |                   |      |                     |      |                     |
 |                   |      |                     |      |                     |
 |                   |      |                     |      |                     |
 +-------------------+      +---------------------+      +---------------------+
 |                   |----->|                     |----->|                     |
 |       mylist      |      |       mylist 2      |      |       mylist 3      |
 |                   |<-----|                     |<-----|                     |
 +-------------------+      +---------------------+      +---------------------+

您有什么作为链表都在里面结构LIST_HEAD 指针指向其他结构LIST_HEAD 秒。请注意,他们不指向结构无论,但对 MYLIST 的那些结构。

What you have as linked list are pointers inside struct list_head that point to other struct list_heads. Note that they don't point to struct whatever, but to the mylist inside those structs.

假设你有一个节点,结构无论是W 。你想找到下一个节点。你能做什么?首先,你可以做 w.mylist.next 来得到下一个节点的指针 MYLIST 。现在,你必须能够提取任何包含该节点的实际结构。这就是 container_of 时:

Say you have a node, struct whatever w. You want to find the next node. What can you do? First, you can do w.mylist.next to get a pointer to the mylist of the next node. Now you have to be able to extract the actual struct whatever containing that node. That's where container_of is used:

struct whatever w_next = container_of(w.mylist.next, struct whatever, mylist);

最后,请注意Linux内核有宏遍历了一个链表的所有节点,这往往不是你想要的东西,所以你实际上并不需要使用 container_of 直接自己。

这篇关于关于在linux container_of宏观疑虑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆