今天看 DPDK 源码时,发现它使用了 glibc 中提供的队列 API,这些 API 包含在
头文件中,易于使用。
今天看了下 man 手册,记录下如何使用这些 API 。
第一种队列是 singly-linked lists。单向链表,插入操作只支持向头部插入,所以通常用来实现 LIFO(后进先出队列)。
第二种队列是 singly-linked tail queues。单向链表,新增了向尾部的插入操作,所以通常用来实现 FIFO(先进先出队列)。
第三种是 lists 。双向链表,插入操作只支持向头部插入。支持双向遍历。
第四种是 tail queues。双向链表,插入操作支持向头部和尾部的插入。支持双向遍历。
下面以 singly-linked lists 为例,介绍如何使用这些 API。
首先要定义一个结构体,例子中使用的结构体名称为 “entry” ,里面除了包含自定义的数据成员(val)外,还必须包含使用 SLIST_ENTRY(TYPE) 定义的一个成员。TYPE 必须是结构体名称 “entry”,成员名称为“entries”可以任意取名。这样我们这个数据结构就能够使用链表 API 管理了。如下所示:
struct entry {
/* 数据 */
int val;
SLIST_ENTRY(entry) entries; /* Singly-linked List. */
}
接着使用 SLIST_HEAD(HEADNAME, TYPE) 定义一个作为链表头部的新结构体,HEADNAME 是新结构体名称,TYPE 是我们自定义的结构体名称。如下所示,例子中使用的新结构体名称为“slisthead”:
SLIST_HEAD(slisthead, entry);
然后定义一个链表头部变量,并初始化:
struct slisthead head = SLIST_HEAD_INITIALIZER(head);
SLIST_INIT(&head);
接下来就可以使用 API 将数据插入到链表了,具体请看下面的个例子。
#include
#include
#include
int main(int argc, char **argv)
{
SLIST_HEAD(slisthead, entry) head = SLIST_HEAD_INITIALIZER(head);
struct slisthead *headp; /* Singly-linked List head. */
struct entry {
int val;
SLIST_ENTRY(entry) entries; /* Singly-linked List. */
} *n1, *n2, *n3, *np;
SLIST_INIT(&head); /* Initialize the list. */
n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
SLIST_INSERT_HEAD(&head, n1, entries);
n2 = malloc(sizeof(struct entry)); /* Insert after. */
SLIST_INSERT_AFTER(n1, n2, entries);
SLIST_FOREACH(np, &head, entries) { /* Forward traversal. */
printf("val = %d\n", np->val);
}
SLIST_REMOVE(&head, n2, entry, entries);/* Deletion. */
free(n2);
n3 = SLIST_FIRST(&head);
SLIST_REMOVE_HEAD(&head, entries); /* Deletion from the head. */
free(n3);
while (!SLIST_EMPTY(&head)) { /* List Deletion. */
n1 = SLIST_FIRST(&head);
SLIST_REMOVE_HEAD(&head, entries);
free(n1);
}
}
#include
#include
#include
int main(int argc, char **argv)
{
STAILQ_HEAD(stailhead, entry) head = STAILQ_HEAD_INITIALIZER(head);
struct stailhead *headp; /* Singly-linked tail queue head. */
struct entry {
int val;
STAILQ_ENTRY(entry) entries; /* Tail queue. */
} *n1, *n2, *n3, *np;
STAILQ_INIT(&head); /* Initialize the queue. */
n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
STAILQ_INSERT_HEAD(&head, n1, entries);
n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */
STAILQ_INSERT_TAIL(&head, n1, entries);
n2 = malloc(sizeof(struct entry)); /* Insert after. */
STAILQ_INSERT_AFTER(&head, n1, n2, entries);
/* Deletion. */
STAILQ_REMOVE(&head, n2, entry, entries);
free(n2);
/* Deletion from the head. */
n3 = STAILQ_FIRST(&head);
STAILQ_REMOVE_HEAD(&head, entries);
free(n3);
/* Forward traversal. */
STAILQ_FOREACH(np, &head, entries) {
printf("val = %d\n", np->val);
}
/* TailQ Deletion. */
while (!STAILQ_EMPTY(&head)) {
n1 = STAILQ_FIRST(&head);
STAILQ_REMOVE_HEAD(&head, entries);
free(n1);
}
/* Faster TailQ Deletion. */
n1 = STAILQ_FIRST(&head);
while (n1 != NULL) {
n2 = STAILQ_NEXT(n1, entries);
free(n1);
n1 = n2;
}
STAILQ_INIT(&head);
}
#include
#include
#include
int main(int argc, char **argv)
{
LIST_HEAD(listhead, entry) head =
LIST_HEAD_INITIALIZER(head);
struct listhead *headp; /* List head. */
struct entry {
int val;
LIST_ENTRY(entry) entries; /* List. */
} *n1, *n2, *n3, *np, *np_temp;
LIST_INIT(&head); /* Initialize the list. */
n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
LIST_INSERT_HEAD(&head, n1, entries);
n2 = malloc(sizeof(struct entry)); /* Insert after. */
LIST_INSERT_AFTER(n1, n2, entries);
n3 = malloc(sizeof(struct entry)); /* Insert before. */
LIST_INSERT_BEFORE(n2, n3, entries);
LIST_REMOVE(n2, entries); /* Deletion. */
free(n2);
/* Forward traversal. */
LIST_FOREACH(np, &head, entries) {
printf("val = %d\n", np->val);
}
while (!LIST_EMPTY(&head)) { /* List Deletion. */
n1 = LIST_FIRST(&head);
LIST_REMOVE(n1, entries);
free(n1);
}
n1 = LIST_FIRST(&head); /* Faster List Deletion. */
while (n1 != NULL) {
n2 = LIST_NEXT(n1, entries);
free(n1);
n1 = n2;
}
LIST_INIT(&head);
}
#include
#include
#include
int main(int argc, char **argv)
{
TAILQ_HEAD(tailhead, entry) head = TAILQ_HEAD_INITIALIZER(head);
struct tailhead *headp; /* Tail queue head. */
struct entry {
int val;
TAILQ_ENTRY(entry) entries; /* Tail queue. */
} *n1, *n2, *n3, *np;
TAILQ_INIT(&head); /* Initialize the queue. */
n1 = malloc(sizeof(struct entry)); /* Insert at the head. */
n1->val = 1;
TAILQ_INSERT_HEAD(&head, n1, entries);
n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */
n1->val = 2;
TAILQ_INSERT_TAIL(&head, n1, entries);
n2 = malloc(sizeof(struct entry)); /* Insert after. */
n2->val = 3;
TAILQ_INSERT_AFTER(&head, n1, n2, entries);
n3 = malloc(sizeof(struct entry)); /* Insert before. */
n3->val = 4;
TAILQ_INSERT_BEFORE(n2, n3, entries);
TAILQ_REMOVE(&head, n2, entries); /* Deletion. */
free(n2);
/* Forward traversal. */
TAILQ_FOREACH(np, &head, entries) {
printf("val = %d\n", np->val);
}
/* Reverse traversal. */
TAILQ_FOREACH_REVERSE(np, &head, tailhead, entries) {
printf("val = %d\n", np->val);
}
/* TailQ Deletion. */
while (!TAILQ_EMPTY(&head)) {
n1 = TAILQ_FIRST(&head);
TAILQ_REMOVE(&head, n1, entries);
free(n1);
}
/* Faster TailQ Deletion. */
n1 = TAILQ_FIRST(&head);
while (n1 != NULL) {
n2 = TAILQ_NEXT(n1, entries);
free(n1);
n1 = n2;
}
TAILQ_INIT(&head);
}