初始化地址散列表

5.1.5 初始化地址散列表

560行,page_address_init()函数,来自mm/highmem.c

 

409void __init page_address_init(void)

 410{

 411        int i;

 412

 413        INIT_LIST_HEAD(&page_address_pool);

 414        for (i = 0; i < ARRAY_SIZE(page_address_maps); i++)

 415                list_add(&page_address_maps[i].list, &page_address_pool);

 416        for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) {

 417                INIT_LIST_HEAD(&page_address_htable[i].lh);

 418                spin_lock_init(&page_address_htable[i].lock);

 419        }

 420        spin_lock_init(&pool_lock);

 421}

 

这个函数很简单,首先413初始化一个链表page_address_pool,这个链表在编译的时候被定义成一个全局变量在同一个文件的309行:

static struct list_head page_address_pool

 

414行,page_address_maps也是个全局变量,来自同一个文件:

static struct page_address_map page_address_maps[LAST_PKMAP];

其每一个元素是一个page_address_map结构:

struct page_address_map {

       struct page *page;

       void *virtual;

       struct list_head list;

};

 

OK,第一次见到我们熟悉的page数据结构了。一个page代表一个物理页面,想要深入了解这方面知识的请访问博客“Linux页框管理”。

ARRAY_SIZE获得数组的元素个数,这里肯定就是LAST_PKMAP了,由于我们没有启动PAE,这个值等于1024,也就是说page_address_maps共有1024个元素。随后415行,1024个循环以后,page_address_pool通过每个page_address_maps的元素的list字段将他们全部链接起来形成个双向循环链表,又page_address_pool作为head

 

416行,page_address_htable,也定义于同一文件:

static struct page_address_slot {

       struct list_head lh;                /* List of page_address_maps */

       spinlock_t lock;                    /* Protect this bucket's list */

} ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER];

 

____cacheline_aligned_in_smp是一个编译优化选项,用于SMP方式的缓存优化。PA_HASH_ORDER被定义为7,所以2^7=128。所以ARRAY_SIZE(page_address_htable)128,那么经过128个循环以后,每个page_address_htable元素的lh都被初始化成一个链表头了,而对于的互斥锁lock也通过spin_lock_init函数进行初始化了。具体的初始化过程请查阅博客“Linux内核入门(三)—— C语言基本功以及“自旋锁”。

 

最后page_address_pool的自旋锁pool_lock初始化之后,函数就结束了。简单归简单,但是大家必须知道这个函数的意义。我们知道一个page结构代表一个4k的页面,我们内核初始化这么一个全局的page_address_mapspage_address_htable这么两个结构,作为页面的地址映射。

 

561行,执行一个printk函数。start_kernel()开始执行至此,会显示“Linux version 2.6.34…”信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
地址法是一种散列表的解决方案。它的实现思路是,对于哈希冲突的键值,将它们存储在同一个链表中。下面是一个使用链地址法实现散列表查找的示例: 首先,定义一个链表节点结构体,包含键值对和指向下一个节点的指针: ``` struct ListNode { int key; int value; ListNode* next; }; ``` 然后,定义散列表结构体,包含一个指向链表头节点的指针数组: ``` const int TABLE_SIZE = 100; struct HashTable { ListNode* table[TABLE_SIZE]; }; ``` 在初始化散列表时,需要将每个链表的头节点初始化为空: ``` void init(HashTable& ht) { for (int i = 0; i < TABLE_SIZE; i++) { ht.table[i] = nullptr; } } ``` 插入操作时,按照键值的哈希值将节点插入到相应的链表中: ``` void insert(HashTable& ht, int key, int value) { int index = hash(key); ListNode* node = new ListNode{key, value, nullptr}; if (ht.table[index] == nullptr) { ht.table[index] = node; } else { ListNode* p = ht.table[index]; while (p->next != nullptr) { p = p->next; } p->next = node; } } ``` 查找操作时,先计算键值的哈希值,然后在相应的链表中查找节点: ``` bool find(HashTable& ht, int key, int& value) { int index = hash(key); ListNode* p = ht.table[index]; while (p != nullptr) { if (p->key == key) { value = p->value; return true; } p = p->next; } return false; } ``` 需要注意的是,哈希函数的设计对散列表的性能影响非常大。一个好的哈希函数应该将键值均匀地分布在散列表中,尽量减少哈希冲突的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值