在 linux 内核中,有大量的数据结构需要用到双向链表,例如进程、文件、模块、页面等。 若采用双向链表的传统实现方式,需要为这些数据结构维护各自的链表,并且为每个链表都 要设计插入、删除等操作函数。因为用来维持链表的 next 和 prev 指针指向对应类型的对 象,因此一种数据结构的链表操作函数不能用于操作其它数据结构的链表。 比如,我们需要分别定义星星和 web 服务器超时的链表结构 :
那么我们如何采用的解决方式是共享链表:
共享链表的形式是这样的:
typedef struct _DoubleLinkNode {
struct _DoubleLinkNode *next; //下一个节点的指针域
struct _DoubleLinkNode *prev;//上一个结点的指针域
}DbLinkNode;
//链表作为挂点放在数据上面
//时钟挂点
typedef struct _ConnTimeout{
int fd;
time_t timeout;
NodeList d;
}ConnTimeout;
//星载挂点
typedef struct _START{
int x;
int y;
int r;
int step;
int statu;
NodeList d;
}START;
如下的一个小demo:
/*
linux内核链表,使用的原因是因为通过一个链表就能实现对多个数结构体的删除
*/
#include<stdio.h>
#include<Windows.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
//结构体指针
typedef struct _DoubleList{
_DoubleList *next;
_DoubleList *prev;
}DoubleList,NodeList;
//时钟挂点
typedef struct _ConnTimeout{
int fd;
time_t timeout;
NodeList d;
}ConnTimeout;
typedef struct _START{
int x;
int y;
int r;
int step;
int statu;
NodeList d;
}START;
//初始化链表
void init(DoubleList &L){
if(!&L) return ;
L.next = NULL;
L.prev = NULL;
}
//插入元素
void insertElemdata(DoubleList &L,DoubleList &node){
//找到最后一个结点
if(!&L||!&node) return ;
DoubleList *last = &L;
while(last->next) last = last->next;
node.next= NULL;
node.prev=last;
last->next = &node;
}
int main(void){
ConnTimeout *t = new ConnTimeout;
ConnTimeout *s =NULL;
init(t->d);
cout<<"请输入5个元素:"<<endl;
for(int i=0;i<5;i++){
//插入元素
s = new ConnTimeout;
cin>>s->fd;
insertElemdata(t->d,s->d);
}
//计算偏移值
int offset = offsetof(ConnTimeout,d);//获取偏移值
DoubleList * p = &(t->d);
while(p->next){
p=p->next;
ConnTimeout *ct = (ConnTimeout*)(size_t(p)-offset);
cout<<ct->fd<<"\t";
}
//销毁链表
printf("\n");
p =&(t->d);
//DoubleList *d;
while(p){
ConnTimeout *ct = (ConnTimeout*)(size_t(p)-offset);
cout<<"删除结点"<<ct->fd<<endl;
p=p->next;
delete ct;
}
system("pause");
return 0;
}