(三)ChannelMap模块的实现
这个模块其实就是为Channel 来服务的,前面讲了Channel 这个结构体里边它封装了文件描述符。假如说我们得到了某一个文件描述符,需要基于这个文件描述符进行它对应的事件处理,那怎么办呢? 我们就需要找到文件描述符对应的那个Channel ,因为在这个Channel 里边有事件对应的回调函数,只有找到Channel 之后,我们才能够知道当读事件被触发了,或者说写事件被触发了。咱们调用的函数是什么呢?在C语言里,没有stl容器的,那如何实现一个对应关系呢?最简单的方式就是使用数组。有一种查找效率更高的数据结构就是哈希,其实它就是通过数组来实现的。 通过空间换时间,牺牲一部分内存空间换取数据的读取效率。看下图,对于每个数组来说,都有一个唯一的下标,是从零开始的,对于文件描述符来说,最小值也是零,所以我们可以让数组的下标去对应文件描述符,0号下标对应0号文件描述符,1号下标对应1号文件描述符。假设说和客户端建立了一个连接,得到了5号文件描述符,那么前边的这些文件描述符是不是有可能是空的?也就是说下标对应的值是空的,这个有关系吗?没关系啊,因为前边说的咱们实现的这种map,主要的思路是空间换时间,所以要换取效率,必然是要牺牲一部分空间的。使用了这种方式,就直接能够通过下标来取出对应的值,不需要遍历。
主要介绍了ChannelMap 的实现思路,包括使用数组和哈希 等数据结构,以及如何通过空间换时间来提高查找效率。同时,还介绍了如何定义map对应的那个结构体,以及如何实例化这个数组。
核心观点:
- 使用数组或哈希等数据结构实现ChannelMap,以提高查找效率。
- 通过空间换时间的思想,牺牲一部分空间来换取效率。
- 在map对应的结构体中,主要的数据成员是一个数组,数组的大小需要根据实际情况确定。
- 需要实例化数组,并确定数组中存储的指针类型。
ChannelMap相关函数
(1) channelMapInit
功能:为ChannelMap分配内存
- 分配内存给指针。
- 计算内存大小:size * 指针的字节数(指针为4字节)。
- 将map指针的地址返回给调用者。
(2) ChannelMapClear
功能:清空ChannelMap结构体。
- 判断map是否为空。
- 遍历数组,释放指针指向的内存(如果指针不为空)。
- 释放数组指向的内存。
- 将数组的size置为0。
注意事项:内存释放分为两部分,数组元素指向的内存和数组本身指向的内存。
(3) makeMapRoom数组扩容函数
功能:判断并扩容ChannelMap 中的list。
- 判断当前list 的size 是否大于newSize。
- 如果需要扩容,调用realloc 函数重新分配更大的内存给list。
注意事项:只有当map 中的size 小于newSize 时才需要进行扩容操作。
- Channel.h
cpp
#pragma once
#include "Channel.h"
struct ChannelMap {
struct Channel** list;
int size;// 记录指针指向的数组的元素总个数
};
// 初始化
struct ChannelMap* channelMapInit(int size);
// 清空map
void ChannelMapClear(struct ChannelMap* map);
// 重新分配内存空间
bool makeMapRoom(struct ChannelMap* map,int newSize,int unitSize);
- Channel.c
cpp
#include "ChannelMap.h"
#include <stdio.h>
#include <stdlib.h>
struct ChannelMap* channelMapInit(int size) {
struct ChannelMap* map = malloc(sizeof(struct ChannelMap));
map->size = size;
map->list = (struct Channel**)malloc(sizeof(struct Channel*) * size);
return map;
}
void ChannelMapClear(struct ChannelMap* map) {
if(map != NULL) {
for(int i=0;i<map->size;++i) {
if(map->list[i] != NULL) {
free(map->list[i]);
}
}
free(map->list);
map->list = NULL;
}
map->size=0;
}
bool makeMapRoom(struct ChannelMap* map,int newSize,int unitSize) {
if(map->size < newSize) {
int curSize = map->size;
// 容量每次扩大原来的一倍
while(curSize < newSize) {
curSize*=2;
}
// 扩容 realloc
struct Channel** temp = realloc(map->list,curSize * unitSize);
if(temp == NULL) {
return false;
}
map->list = temp;
memset(&map->list[map->size],0,(curSize - map->size) * unitSize);
map->size = curSize;
}
return true;
}
第一个精彩片段:channelMapInit 函数的实现,详细介绍了如何为ChannelMap 分配内存,包括计算内存大小和返回map指针的地址。对于理解ChannelMap如何创建和初始化非常重要,有助于理解后续的函数如何工作。
第二个精彩片段:ChannelMapClear 函数的实现,详细介绍了如何清空ChannelMap 结构体,包括释放内存和重置size。 这个片段对于理解如何管理和释放内存资源非常重要,有助于避免内存泄漏和其他相关问题。
内容概要:详细介绍了三个函数:channelMapInit 、ChannelMapClear 和makeMapRoom 对数组扩容函数的实现。这三个函数用于创建、初始化、清空和释放ChannelMap的内存,以及在必要时扩容数组。
核心观点:
- channelMapInit 函数主要负责为ChannelMap分配内存,包括为指针成员分配内存,并根据元素个数和指针的字节数计算内存大小。
- ChannelMapClear 函数用于清空ChannelMap 结构体,包括释放数组元素指向的内存和数组本身指向的内存,并将数组的size置为0。
- 对数组扩容函数需要判断当前数组的size 是否小于newSize ,如果需要扩容,则调用realloc函数重新分配更大的内存给数组。