DELAY INIT 延迟初始化
全局變量,全局對象初始化,很方便。但過多的全局初始化,會導致程序啟動時間過慢,還有全局初始化順序不好控制(連接器可以可以控制文件之間的順序,但那需要寫好makefile, 并放映程序的實際依賴,沒做到DRY).
?
我使用了內核的list_head 結構了組織初始化函數, 每個文件有一個file_node的結構來保持本文件內的初始化函數,file_node會注冊的全局的一個分級數組中, file_node有個depend鏈表,保持了這個文件要依賴的其它文件。這樣就實現了程序初始化順序的管理。
?
delay_init.h
#ifndef __DELAY_INIT_H__
#define __DELAY_INIT_H__
#include "list.h"
namespace delay_init {
typedef int (*callback)(void);
struct file_node {
??? char const *file_name;
??? int called;
??? list_head init_list;
??? list_head depend_list;
??? list_head link_to_root;
};
#define DELAY_INIT_FILE_NODE_INIT(name) \
??????? {\
??????????? __BASE_FILE__,\
??????????? 0,\
??????????? LIST_HEAD_INIT(name.init_list),\
??????????? LIST_HEAD_INIT(name.depend_list),\
??????????? LIST_HEAD_INIT(name.link_to_root)\
??????? }
#define DELAY_INIT_FILE_NODE(name)???? delay_init::file_node name = DELAY_INIT_FILE_NODE_INIT(name)
struct delay_init_struct {
??? list_head link_to_file;
??? callback init;
??? char const *info;
??? int called;
};
#define DELAY_INIT_STRUCT_INIT(name) \
??????? {LIST_HEAD_INIT(name.link_to_file), 0, 0, 0}
#define DELAY_INIT_STRUCT(name)? delay_init::delay_init_struct name=DELAY_INIT_STRUCT_INIT(name)
struct delay_init_depend_struct {
??? list_head link_to_depend;
??? file_node **point_file_node;
};
#define DELAY_INIT_DEPEND_STRUCT_INIT(name)\
??????? {LIST_HEAD_INIT(name.link_to_depend), 0}
#define DELAY_INIT_DEPEND_STRUCT(name)? delay_init::delay_init_depend_struct name = DELAY_INIT_DEPEND_STRUCT_INIT(name)
#define INIT_LEVEL_NUM 10
#define INIT_LOG_LEVEL 3
#define INIT_CONF_LEVEL 2
#define INIT_CONF_IOC_LEVEL 1
#define INIT_FIRST_LEVEL 0
#define INIT_LAST_LEVEL (INIT_LEVEL_NUM-1)
extern list_head g_delay_init_list_head[INIT_LEVEL_NUM];
int call_all_level();
int call_in_level(int level);
extern int failed_cnt;
extern int success_cnt;
extern int total_cnt;
extern int called_cnt;
}
#define MACRO_NAME_CONCAT2(a,b) MACRO_NAME_CONCAT2_PRITIVE(a,b)
#define MACRO_NAME_CONCAT2_PRITIVE(a,b) a##b
#define STRING_NAME(name) STRING_NAME_IMPL(name)
#define STRING_NAME_IMPL(name) #name
inline
int __one_call_call_fun__(void(*fun)(void)) {
??? fun();
??? return 1;
}
#define ONCE_CALL_FUNC(name) MACRO_NAME_CONCAT2(__func_once_call_ ,name)
#define ONCE_CALL_VAR(name) MACRO_NAME_CONCAT2(__var_once_call_, name)
#define ONCE_CALL_WITH(name) \
???????? static void ONCE_CALL_FUNC(name)(void); \
???????? static int ONCE_CALL_VAR(name) = __one_call_call_fun__(&ONCE_CALL_FUNC(name)); \
???????? static void ONCE_CALL_FUNC(name)(void)
#define ONCE_CALL ONCE_CALL_WITH(MACRO_NAME_CONCAT2(__COUNTER__,__LINE__))
static DELAY_INIT_FILE_NODE(_this_file_node_delay_init_);
ONCE_CALL_WITH(delay_init_add_file_to_root)
{
??? list_add_tail(&_this_file_node_delay_init_.link_to_root,
??????????? &delay_init::g_delay_init_list_head[INIT_LAST_LEVEL]);
}
#define DELAY_INIT_IN_LEVEL(level) \
ONCE_CALL \
{\
??? list_move_tail(&_this_file_node_delay_init_.link_to_root, &delay_init::g_delay_init_list_head[level]);\
}
#define DELAY_INIT_NAME(name) MACRO_NAME_CONCAT2(MACRO_NAME_CONCAT2(__delay_init_def_, name), __LINE__)
#define DELAY_INIT \
???????? static int DELAY_INIT_NAME(init_fun)(void); \
???????? static DELAY_INIT_STRUCT(DELAY_INIT_NAME(init_node));\
???????? ONCE_CALL { \
???????????? DELAY_INIT_NAME(init_node).init =&DELAY_INIT_NAME(init_fun);\
???????????? DELAY_INIT_NAME(init_node).info = \
??????????????? "delay init name:" __FILE__ "_" STRING_NAME(__LINE__)\
??????????????? " call in:" __FILE__ " line:" STRING_NAME(__LINE__); \
??????????? list_add_tail(&DELAY_INIT_NAME(init_node).link_to_file, &_this_file_node_delay_init_.init_list);\
???????????? return ;\
??????? }\
??????? static int DELAY_INIT_NAME(init_fun)(void)
#define DELAY_INIT_EXPORT_NAME(name) MACRO_NAME_CONCAT2(__delay_init_export_name_, name)
#define DELAY_INIT_EXPORT(name) \
??????? delay_init::file_node * DELAY_INIT_EXPORT_NAME(name) = & _this_file_node_delay_init_;
#define DEPEND_ON_DELAY_INIT_NAME(name) MACRO_NAME_CONCAT2(name, MACRO_NAME_CONCAT2(__delay_init_depend_struct_, __LINE__))
#define DEPEND_ON_DELAY_INIT(name)\
??????? extern delay_init::file_node * DELAY_INIT_EXPORT_NAME(name);\
??????? static DELAY_INIT_DEPEND_STRUCT(DEPEND_ON_DELAY_INIT_NAME(_struct_));\
??????? ONCE_CALL {\
??????????? DEPEND_ON_DELAY_INIT_NAME(_struct_).point_file_node = &DELAY_INIT_EXPORT_NAME(name);\
??????????? list_add_tail(&DEPEND_ON_DELAY_INIT_NAME(_struct_).link_to_depend, &_this_file_node_delay_init_.depend_list);\
??????? }
#endif //__DELAY_INIT_H__
?
delay_init.cpp
#include "delay_init.h"
#include "repeat_macro.h"
#ifndef LOG
#define ENABLE_DELAY_INIT_CPP_LOG
#include <stdio.h>
#define LOG(level, format, ...)\
??? fprintf(stderr, "[%s][%s][%d]: " format "\n", #level, __FILE__, int(__LINE__), ##__VA_ARGS__)
#endif //LOG
namespace delay_init {
int failed_cnt = 0;
int success_cnt = 0;
int total_cnt = 0;
int called_cnt = 0;
#define INIT_LIST_HEAD_IMPL(s, index, name) COMMA_IF(index) LIST_HEAD_INIT(name[index])
#define LIST_HEAD_ARRAY_INIT(name, n) { EXPR(0)(REPEAT(0, n, INIT_LIST_HEAD_IMPL, name)) }
#define LIST_HEAD_ARRAY(name, n) list_head name[n] =? LIST_HEAD_ARRAY_INIT(name, n)
LIST_HEAD_ARRAY(g_delay_init_list_head, INIT_LEVEL_NUM);
static int call_file_list(file_node *file_list) {
??? if (file_list->called) {
??????? return 0;
??? }
??? LOG(DEBUG, "delay_init in file: %s", file_list->file_name);
??? int ret = 0;
??? list_head *q = NULL;
??? list_for_each(q, &file_list->depend_list) {
??????? delay_init_depend_struct *depend =
??????????????? container_of(q, delay_init_depend_struct, link_to_depend);
??????? if (*(depend->point_file_node)) {
??????????? ret += call_file_list(*(depend->point_file_node));
??????? }
??? }
??? list_for_each(q, &file_list->init_list) {
??????? delay_init_struct *st =
??????????????? container_of(q, delay_init_struct, link_to_file);
??????? callback init = st->init;
??????? if (init) {
??????????? if (0 == st->called) {
??????????????? LOG(DEBUG, "call delay init func:%s", st->info);
??????????????? ret += init();
??????????????? ++st->called;
??????????????? ++called_cnt;
??????????? }
??????????? ++success_cnt;
??????? } else {
??????????? ++failed_cnt;
??????? }
??????? ++total_cnt;
??? }
??? ++(file_list->called);
??? return ret;
}
int call_in_level(int level) {
??? if (level < 0 || INIT_LEVEL_NUM - 1 < level) {
??????? LOG(ERROR, "error init level [%d] group", level);
??????? return -1;
??? }LOG(DEBUG, "delay_init in level: %d", level);
??? int ret = 0;
??? list_head *q = NULL;
??? list_for_each(q, &g_delay_init_list_head[level]) {
??????? file_node * file_list = container_of(q, file_node, link_to_root);
??????? ret += call_file_list(file_list);
??? }
??? return ret;
}
int call_all_level() {
??? int ret = 0;
??? for (int i = 0; i < INIT_LEVEL_NUM; ++i) {
??????? ret += call_in_level(i);
??? }
??? return ret;
}
}
#ifdef ENABLE_DELAY_INIT_CPP_LOG
#undef LOG
#undef ENABLE_DELAY_INIT_CPP_LOG
#endif //ENABLE_DELAY_INIT_CPP_LOG
?
使用范例
?
log.h
#ifndef __LOG_IMPL__
DEPEND_ON_DELAY_INIT(log)
#endif //__LOG_IMPL__
?
這樣,所有使用了 log.h的程序,都會先初始化好log
?
log.cpp
#define __LOG_IMPL__
#include "log.h"
…….
DELAY_INIT
{
……
}
DELAY_INIT_EXPORT(log)
main.cpp
delay_init::call_all_level();
轉載于:https://www.cnblogs.com/napoleon_liu/archive/2010/12/10/1902322.html
總結
以上是生活随笔為你收集整理的DELAY INIT 延迟初始化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows Phone 7范例游戏P
- 下一篇: Portlet开发指南第二章