关于linux内核中 等待队列 数据结构之思考
2010-12-02 10:51
260 查看
关于linux等待队列,大体有如下描述:
等待队列是一个双向循环链表,在这个链表中,有两种数据结构:等待队列头(wait_queue_head_t)和等待队列项(wait_queue_t)。
等待队列头和等待队列项中都包含一个list_head类型的域作为"连接件"。
等待对头wait_queue_head_t 和等待队列元素wait_queue_t的定义如下:
//队头结构
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
//队列元素结构
struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
从队头和队列元素的定义中,可以看出,都包含了list_head类型的结构,而这个结构中只保存了向前和向后的指针。定义如下。
struct list_head {
struct list_head *next, *prev;
};
看到这里就有些纳闷了,为什么这些方向指针和外面的结构体是分开的,也就是说,实际的指向关系只是这些方向指针之间的关系,而其他元素是附加在这些指针之上的。和我们传统的数据结构中的链表定义有很大的不同。
由此,又产生了一个疑问:那通过这些指针来获得具体的队列元素属性的时候,岂不是很不方便?(需要通过结构体某个成员的地址来计算该结构体的的地址?联想到之前学校的函数container_of或许可以完成此功能)
好奇心驱使下,最终了解了内核中队列的wakeup函数的实现,果不其然,在list_entry的定义中,找到了container_of的调用。
具体调用关系如下:
__wake_up_common--》list_for_each_entry_safe——》list_entry——》container_of
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int wake_flags, void *key)
{
wait_queue_t *curr, *next;
list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
unsigned flags = curr->flags;
if (curr->func(curr, mode, wake_flags, key) &&
(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
break;
}
}
#define list_for_each_entry_safe(pos, n, head, member) /
for (pos = list_entry((head)->next, typeof(*pos), member), /
n = list_entry(pos->member.next, typeof(*pos), member); /
&pos->member != (head); /
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_entry(ptr, type, member) /
container_of(ptr, type, member)
等待队列是一个双向循环链表,在这个链表中,有两种数据结构:等待队列头(wait_queue_head_t)和等待队列项(wait_queue_t)。
等待队列头和等待队列项中都包含一个list_head类型的域作为"连接件"。
等待对头wait_queue_head_t 和等待队列元素wait_queue_t的定义如下:
//队头结构
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
//队列元素结构
struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
从队头和队列元素的定义中,可以看出,都包含了list_head类型的结构,而这个结构中只保存了向前和向后的指针。定义如下。
struct list_head {
struct list_head *next, *prev;
};
看到这里就有些纳闷了,为什么这些方向指针和外面的结构体是分开的,也就是说,实际的指向关系只是这些方向指针之间的关系,而其他元素是附加在这些指针之上的。和我们传统的数据结构中的链表定义有很大的不同。
由此,又产生了一个疑问:那通过这些指针来获得具体的队列元素属性的时候,岂不是很不方便?(需要通过结构体某个成员的地址来计算该结构体的的地址?联想到之前学校的函数container_of或许可以完成此功能)
好奇心驱使下,最终了解了内核中队列的wakeup函数的实现,果不其然,在list_entry的定义中,找到了container_of的调用。
具体调用关系如下:
__wake_up_common--》list_for_each_entry_safe——》list_entry——》container_of
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int wake_flags, void *key)
{
wait_queue_t *curr, *next;
list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
unsigned flags = curr->flags;
if (curr->func(curr, mode, wake_flags, key) &&
(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
break;
}
}
#define list_for_each_entry_safe(pos, n, head, member) /
for (pos = list_entry((head)->next, typeof(*pos), member), /
n = list_entry(pos->member.next, typeof(*pos), member); /
&pos->member != (head); /
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_entry(ptr, type, member) /
container_of(ptr, type, member)
相关文章推荐
- 关于linux内核中 等待队列 数据结构之思考
- 【数据结构与算法】关于二叉查找树的思考
- 关于linux内核中等待队列的问题!
- 数据结构5-关于链队列的实例,打印链队列中内容
- 如何清晰地思考:近一年来业余阅读的关于思维方面的知识结构整理(附大幅思维导图)
- 数据结构实践—— 负数把正数赶出队列
- 数据结构(7)--队列
- 数据结构之队列
- 数据结构---队列
- linux内核中等待队列
- PHP实现队列(Queue)数据结构
- [翻译]C#数据结构与算法 – 第五章栈与队列(Part 2)
- 数据结构(C实现)------- 顺序队列(循环队列之少用一个存储空间实现) .
- 数据结构之单调栈单调队列模板
- 线性表数据结构解读(四)队列结构Queue
- 数据结构之队列
- Linux内核中的等待队列--init_waitqueue_head等
- 数据结构——队列
- 温习之数据结构——队列
- 数据结构实验之队列一:排队买饭