Page 506 - 《软件学报》2024年第4期
P. 506

2084                                                       软件学报  2024  年第  35  卷第  4  期


                    榫卯框架中使用高阶函数复合各层级函数, 其                C  宏实现如图   4  所示. 对于一个层级函数而言, 它至少需要实
                 现  4  个层级函数接口   create_obj, alloc_obj, free_obj 和  getmeta_obj, 分别用于线程创建时初始化内存请求上下文中
                 的层级对象, 处理分配和释放内存请求, 以及获取内存对象的元数据. 层级函数接口的输入参数包含内存请求上下
                 文  mctx_t 和已完成连接的层级函数       lfunc_t 的接口. 图  4  给出了一个简单层级函数的实现示例, 该层级函数用于统
                 计指定大小内存申请和释放次数. 对开发者而言, 编写一个层级函数只需要关注本层提供的功能以及相关数据结
                 构, 而无需考虑其上层或下层代码. 一个完整的内存分配器构建过程首先需要使用                          DEFINE_OSLAYER  完成系统
                 接口层的定义, 然后通过       LAYER_COMPOSE   高阶函数将多个层级函数连接.

                                                                          一个简单基础层级函数实现示例
                   // 可连接的层级函数定义                                    该层级函数用于统计指定大小内存申请和释放的次数
                   typedef mctx_t * lfunc_t (mctx_t *ctx);
                                                                // 声明层级
                   #define __DECLARE_OBJ_FUNC (func_name) \     DECLARE_LA YER(count)
                   static inline mctx_t * func_name##_obj(mctx_t *ctx, lfunc_t *ufunc);  // 层级对象结构体定义
                                                                typedef struct{
                   // 每一层至少需要实现的层级函数                             unsigned long alloc_count;
                   #define DECLARE_LA YER(layer_name) \          unsigned long free_count;
                   MAP(__DECLARE_OBJ_FUNC , layer_name##_create,  }count_obj_t ;
                   layer_name##_alloc, layer_name##_free, layer_name##_getmeta)
                                                                count_obj_t count_obj_global;
                   #define __LFUNC_COMPOSABLE (unlinkedf, linkedf) \  // 将储存层级数据的对象指针记录到线程的内存上下文中
                   static inline mctx_t *__linked_##unlinkedf (mctx_t *ctx)  static inline mctx_t * count_cr eate_obj (mctx_t *ctx, lfunc_t *ufunc){
                   { return unlinkedf (ctx, linkedf);}           // 此处所有线程共享一个全局对象指针
                                                                 mctx_setlayer_obj (ctx, &count_obj_global);
                   // 定义系统接口使用的辅助函数                              // 若线程私有对象指针则使用 os_alloc接口分配线程私有的空间
                   #define __OS_LAYER(layer_type) \              return ufunc (ctx);
                   __LFUNC_COMPOSABLE (layer_type##_obj, NULL )  }
                   // 用于复合层级函数的辅助函数                             static inline mctx_t * count_alloc_obj (mctx_t *ctx, lfunc_t *ufunc){
                   #define __LCOMPOSE (linkedl1_type, l2_type) \  // 使用分级管理策略判断是否直接跳过本级
                   __LFUNC_COMPOSABLE (l2_type##_obj, __linked_##linkedl1_type##_obj )  MATCH_HANDLE_SIZE (count, ctx->rsize, ctx, ufunc);
                                                                 // 获取当前层级对象
                   #define __LCOMPOSE_TYPE (l1, l2, type) \      count_obj_t *l = (count_obj_t *)mctx_getlayer_obj (ctx);
                   __LCOMPOSE (l1##_##type, l2##_##type)         debug_printf ("count alloc size %llu\n", ctx->rsize);
                                                                 // 增加统计计数
                   // 定义系统接口层函数                                  FAA(&l->alloc_count, 1);
                   #define DEFINE_OSLA YER(alayer) \             // 内存请求转交给上级处理
                   MAP(__OS_LAYER, alayer##_create,              return ufunc (ctx);
                   alayer##_alloc, alayer##_free, alayer##_getmeta)  }
                   // 层级连接,进行三种函数的复合                            static inline mctx_t * count_fr ee_obj (mctx_t *ctx, lfunc_t *ufunc){
                   #define __LAYER_CONNECT (linkedl1, l2) \      // ...
                   __LCOMPOSE_TYPE (linkedl1, l2, create) \     }
                   __LCOMPOSE_TYPE (linkedl1, l2, alloc) \
                   __LCOMPOSE_TYPE (linkedl1, l2, free) \       static inline mctx_t * count_getmeta_obj (mctx_t *ctx, lfunc_t *ufunc){
                   __LCOMPOSE_TYPE (linkedl1, l2, getmeta)       // 该层不负责管理内存对象的元数据 ,直接交给上层处理
                                                                 return ufunc (ctx);
                   // 使用FOLD LEFT连接整个层级函数链表                     }
                   #define LAYER_COMPOSE (...) \
                   FOLDL (__LAYER_CONNECT , __VA_ARGS__)
                                       图 4 榫卯框架的实现细节与一个简单的层级函数示例

                    由于  C  语言并不支持函数式编程, 因此实现函数的复合还需要用到                   C  预处理的元编程特性. 层级函数的复合
                 主要依靠高阶函数       LAYER_CONNECT  实现. 该高阶函数要求输入一个上级已完成连接的层级函数和未完成连接
                 的层级函数, 输出一个完成连接的层级函数__linked_layer_type_obj. 在编译预处理阶段, C               预处理器会展开相关
                 宏, 替换宏参数从而实现中间函数的生成与函数的复合. 此外, 图                    4  中所使用的函数式编程中常用的高阶函数
                 MAP  和  FOLDL  依赖  C99  标准可变参数宏机制以及     C++20  标准可递归宏机制. 其中      MAP  接受一个函数     f 和一串
                 输入, 将每个输入传入       f 执行; FOLDL  则将前一次输出与下一次输入一同传入函数               f, 递归产生输出. 由于这两个
                 高阶宏函数的     C  实现较为复杂且有相应开源代码库           macrofun  可供参考, 本文在此不再赘述其具体实现.
                    在榫卯框架中, 可复合的层级函数分为系统接口层函数, 基础层函数和用户接口层函数                            3  种, 其中基础层函数
                 允许存在多个, 而系统接口层函数和用户接口层函数只允许最多                     1  个, 分别位于层级顺序的第      1  个和最后  1  个. 榫
   501   502   503   504   505   506   507   508   509   510   511