数据结构(3)内核链表

一、内核链表

        内核链表是一种在操作系统内核中使用的数据结构,主要用于管理和组织内核对象。它是有头双向链表的一种实现。

内核链表的特点
  1. 双向链表: 内核链表的每个节点都包含指向前一个节点和后一个节点的指针,这使得在链表中进行插入和删除操作时更加高效。

  2. 高效性: 内核链表的操作通常在内核空间中进行,避免了用户空间和内核空间之间的上下文切换,从而提高了性能。

  3. 简化的接口: 内核链表通常提供了一组宏和函数来简化链表的操作,例如添加、删除和遍历节点。这些操作通常是以宏的形式实现,以减少函数调用的开销。

1. offsetof

offsetof 是一个宏,用于获取结构体中某个成员相对于结构体起始位置的字节偏移量。它的定义通常如下:

#define offsetof(type, member) ((size_t) &((type *)0)->member)
用法
  • 参数:

    • type: 结构体的类型。
    • member: 结构体中的成员名。
  • 返回值: 返回指定成员相对于结构体起始位置的字节偏移量。

2. container_of

container_of 是一个宏,用于根据结构体成员的指针获取包含该成员的结构体的指针。它的定义通常如下:

#define container_of(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member)))
用法
  • 参数:

    • ptr: 指向结构体成员的指针。
    • type: 结构体的类型。
    • member: 结构体中的成员名。
  • 返回值: 返回指向包含该成员的结构体的指针。

二、内核链表的实现

KNode_t:

代表链表中的一个节点。
包含两个指针:
ppre: 指向前一个节点的指针。
pnext: 指向下一个节点的指针。
typedef struct knode  
{  
    struct knode *ppre;  
    struct knode *pnext;  
} KNode_t;  
KLink_t:

代表整个链表。
包含以下成员:
phead: 指向链表头节点的指针。
clen: 当前链表中的节点数量。
mutex: 用于线程安全的互斥锁,确保在多线程环境中对链表的操作是安全的。
typedef struct klink  
{  
    KNode_t *phead;  
    int clen;  
    pthread_mutex_t mutex;  
} KLink_t;  
1. create_klink
KLink_t *create_klink()  
{  
    KLink_t *pklink = malloc(sizeof(KLink_t));  
    if (NULL == pklink)  
    {  
        perror("fail malloc");  
        return NULL;  
    }  
    pklink->phead = NULL;  
    pklink->clen = 0;  
    pthread_mutex_init(&(pklink->mutex), NULL);  

    return pklink;  
}  
功能: 创建一个新的链表。
步骤:
使用 malloc 分配内存。
检查内存分配是否成功。
初始化链表头指针为 NULL,节点计数为 0,并初始化互斥锁。
返回值: 返回指向新链表的指针。
2. push_klink_head
int push_klink_head(KLink_t *pklink, void *p)  
{  
    KNode_t *pnode = (KNode_t *)p;  
    pnode->pnext = NULL;  
    pnode->ppre = NULL;  

    pnode->pnext = pklink->phead;  
    if (pklink->phead != NULL)  
    {  
        pklink->phead->ppre = pnode;  
    }  
    pklink->phead = pnode;  

    pklink->clen++;  

    return 0;  
}  
功能: 将一个节点插入到链表的头部。
步骤:
将传入的节点指针 p 转换为 KNode_t 类型。
设置新节点的前后指针。
将新节点插入到链表头部,并更新头指针。
增加链表的节点计数。
返回值: 返回 0 表示成功。
3. klink_for_each
void klink_for_each(KLink_t *pklink, void (*pfun)(void *))  
{  
    KNode_t *pnode = pklink->phead;  
    while (pnode != NULL)  
    {  
        pfun(pnode);  
        pnode = pnode->pnext;  
    }  
    printf("\n");  
}  
功能: 遍历链表并对每个节点执行指定的函数。
参数:
pklink: 指向链表的指针。
pfun: 指向处理每个节点的函数的指针。
步骤:
从链表头开始遍历,调用传入的函数处理每个节点。
4. push_klink_tail
int push_klink_tail(KLink_t *pklink, void *q)  
{  
    KNode_t* pnode = (KNode_t*)q;  
    pnode->pnext = NULL;  
    pnode->ppre = NULL;  
    if (NULL == pklink->phead)  
    {  
        pklink->phead = pnode;    
    }  
    KNode_t* p = pklink->phead;  
    while (p->pnext)  
    {  
        p = p->pnext;  
    }  
    p->pnext = pnode;  
    pnode->ppre = p;  
    return 0;  
}  
功能: 将一个节点插入到链表的尾部。
步骤:
将传入的节点指针 q 转换为 KNode_t 类型。
设置新节点的前后指针。
如果链表为空,将新节点设置为头节点。
否则,遍历到链表的最后一个节点,并将新节点添加到尾部。
返回值: 返回 0 表示成功。
5. pop_klink_head
int pop_klink_head(KLink_t *pklink)  
{  
    if (NULL == pklink->phead)  
    {  
        return 0;  
    }  
    KNode_t* pnode = pklink->phead;  
    pklink->phead = pnode->pnext;  
    if (pklink->phead != NULL)  
    {  
        pklink->phead->ppre = NULL;  
    }  
    free(pnode);  
    return 0;  
}  
功能: 从链表的头部删除一个节点。
步骤:
检查链表是否为空。
保存当前头节点,并将头指针更新为下一个节点。
如果新的头节点不为空,更新其前指针。
释放被删除节点的内存。
返回值: 返回 0 表示成功。

三、内核链表和普通双向链表的区别

1. 目的和使用场景
  • 内核链表:

    • 主要用于操作系统内核中,处理任务调度、资源管理、设备驱动等。
    • 需要高效的插入、删除和遍历操作,以满足实时性和性能要求。
  • 普通双向链表:

    • 通常用于应用程序中,处理数据存储、缓存、队列等。
    • 设计上更关注易用性和灵活性,而不是极端的性能优化。
2. 结构和实现
  • 内核链表:

    • 通常使用更简洁的结构,可能不包含数据部分,节点结构只包含指向前后节点的指针。
    • 数据部分通常与链表分开,链表节点只负责链接,数据通过其他方式管理。
  • 普通双向链表:

    • 节点结构通常包含数据部分和指向前后节点的指针。
    • 每个节点都是完整的,包含数据和指针,便于直接操作。
3. 线程安全
  • 内核链表:

    • 设计时通常考虑到多线程环境,可能会使用互斥锁或其他同步机制来确保线程安全。
    • 需要处理并发访问,确保数据一致性。
  • 普通双向链表:

    • 通常不考虑线程安全,使用时需要开发者自行管理。
    • 在单线程环境中使用时,简单易用,但在多线程环境中可能会出现数据竞争问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值