1. 断言assert和堆栈调用情况打印

来自**util.h****util.cpp**文件
目的:系统自带assert触发后报错信息过于简单,希望将报错内容和位置细化一些,实现一个简单的异常跟踪与堆栈情况打印,方便调试。

头文件:<assert.h><execinfo.h>

  • 堆栈打印封装如下: ```cpp //获取函数堆栈 void BackTrace(std::vector& bt, int size, int skip) { void arr = (void)malloc(sizeof(void ) size);

    //返回当前堆栈使用的真实层数 size是期望层数上限 size_t true_size = backtrace(arr, size);

    //这里面有malloc的过程 strings是一块动态分配内存 char **strings = backtrace_symbols(arr, true_size); if(strings == nullptr) {

    1. KIT_LOG_ERROR(g_logger) << "BackTrace: backtrace_symbols error";
    2. return;

    }

    for(size_t i = skip;i < true_size;++i) {

    1. bt.push_back(strings[i]);

    }

    free(strings); free(arr); }

//打印函数堆栈 std::string BackTraceToString(int size, const std::string &prefix, int skip) { std::vector bt; BackTrace(bt, size, skip);

  1. //借助流 输出
  2. std::stringstream ss;
  3. for(size_t i = 0;i < bt.size();++i)
  4. {
  5. ss << prefix << bt[i] << std::endl;
  6. }
  7. return ss.str();

}

  1. - **宏函数封装如下:**
  2. **来自**`**marco.h**`**文件**
  3. ```clojure
  4. #define KIT_ASSERT(x) do{\
  5. if(!(x)){\
  6. KIT_LOG_ERROR(KIT_LOG_ROOT()) << "\nASSERTION: " #x \
  7. << "\nbacktrace: \n" \
  8. << kit_server::BackTraceToString(100, " ");\
  9. assert(x);\
  10. }\
  11. }\
  12. while(0)
  13. //第二个参数可做一些补充说明
  14. #define KIT_ASSERT2(x, w)do{\
  15. if(!(x)){\
  16. KIT_LOG_ERROR(KIT_LOG_ROOT()) << "\nASSERTION: " #x \
  17. << "\n" << #w \
  18. << "\nbacktrace: \n" \
  19. << kit_server::BackTraceToString(100, " ");\
  20. assert(x);\
  21. }\
  22. }\
  23. while(0)

2. 获取当前系统时间

来自**util.h****util.cpp**文件

使用getofday()函数能够获取到us级别的系统时间,较为精确,也方便向其他精度的时间单位上去转化

  1. //获取ms级时间
  2. uint64_t GetCurrentMs()
  3. {
  4. struct timeval tv;
  5. gettimeofday(&tv, nullptr);
  6. return tv.tv_sec * 1000ul + tv.tv_usec / 1000;
  7. }
  8. //获取us级时间
  9. uint64_t GetCurrentUs()
  10. {
  11. struct timeval tv;
  12. gettimeofday(&tv, nullptr);
  13. return tv.tv_sec * 1000 * 1000ul + tv.tv_usec;
  14. }

3. 获取线程、协程信息

来自**util.h****util.cpp**文件

3.1 获取线程ID和线程名称

  1. pid_t GetThreadId()
  2. {
  3. //返回内核中tid 不使用pthread_self()是因为其返回的不是真正线程ID
  4. return syscall(SYS_gettid);
  5. }
  6. const std::string& GetThreadName()
  7. {
  8. //返回内核中tid 不使用pthread_self()是因为其返回的不是真正线程ID
  9. return Thread::_getName();
  10. }

3.2 获取协程ID

  1. uint64_t GetCoroutineId()
  2. {
  3. return Coroutine::GetCoroutineId();
  4. }

4. if-else条件判断编译优化

来自**marco.h**文件

  1. //编译器优化
  2. #if defined __GNUC__ || defined __llvm__
  3. # define KIT_LIKELY(x) __builtin_expect(!!(x), 1)
  4. # define KIT_UNLIKELY(x) __builtin_expect(!!(x), 0)
  5. #else
  6. # define KIT_LIKELY(x) (x)
  7. # define KIT_UNLIKELY(x) (x)
  8. #endif

5. 文件通用操作类封装

来自**util.h****util.cpp**文件

  1. /**
  2. * @brief 文件通用操作类
  3. */
  4. class FSUtil
  5. {
  6. public:
  7. /**
  8. * @brief 获取当前文件夹路径下所有的文件
  9. * @param[out] files 输出当前路径下所有文件的名称
  10. * @param[in] path 当前要操作的文件夹的路径
  11. * @param[in] subfix 指定的后缀名
  12. */
  13. static void ListAllFile(std::vector<std::string>& files,
  14. const std::string& path, const std::string& subfix);
  15. /**
  16. * @brief 创建一个目录
  17. * @param[in] dirname 目录名称
  18. * @return 返回是否成功创建了目录
  19. */
  20. static bool Mkdir(const std::string& dirname);
  21. };

5.1 获取某一个文件夹路径下所有的指定目标文件

  1. /**
  2. * @brief 获取当前文件夹路径下所有的文件
  3. * @param[out] files 输出当前路径下所有文件的名称
  4. * @param[in] path 当前要操作的文件夹的路径
  5. * @param[in] subfix 指定的后缀名
  6. */
  7. void FSUtil::ListAllFile(std::vector<std::string>& files,
  8. const std::string& path, const std::string& subfix)
  9. {
  10. //探测目录是否存在
  11. if(access(path.c_str(), F_OK) < 0)
  12. {
  13. KIT_LOG_ERROR(g_logger) << "file path don't exist access error, errno="
  14. << errno << ", is:" << strerror(errno);
  15. return;
  16. }
  17. //打开目录流
  18. DIR* dir = opendir(path.c_str());
  19. if(!dir)
  20. {
  21. KIT_LOG_ERROR(g_logger) << "open dir error, errno=" << errno
  22. << ",is:" << strerror(errno);
  23. return;
  24. }
  25. //从目录流中读取文件信息
  26. struct dirent* dp = nullptr;
  27. errno = 0;
  28. while((dp = readdir(dir)) != nullptr)
  29. {
  30. //如果是一个文件夹类型 需要继续读取 进行递归
  31. if(dp->d_type == DT_DIR)
  32. {
  33. //把当前目录路径和父目录路径过滤
  34. if(strcmp(dp->d_name, ".") == 0 ||
  35. strcmp(dp->d_name, "..") == 0)
  36. continue;
  37. ListAllFile(files, path + "/" + dp->d_name, subfix);
  38. }
  39. else if(dp->d_type == DT_REG) //如果是一个普通文件
  40. {
  41. std::string file_name = dp->d_name;
  42. //如果 传入后缀为空 默认收集所有文件
  43. if(!subfix.size())
  44. {
  45. files.push_back(path + "/" + file_name);
  46. }
  47. else
  48. {
  49. //文件名比传入后缀还要短 就不是我们要找的文件
  50. if(file_name.size() < subfix.size())
  51. continue;
  52. //截取出后缀 如果为目标文件要收集起来
  53. if(file_name.substr(file_name.length() - subfix.size()) == subfix)
  54. {
  55. files.push_back(path + "/" + file_name);
  56. }
  57. }
  58. }
  59. }
  60. //关闭目录流
  61. closedir(dir);
  62. //判断readir()函数是否出错
  63. if(errno != 0)
  64. {
  65. KIT_LOG_ERROR(g_logger) << "readdir error, errnn=" << errno
  66. << ",is:" << strerror(errno);
  67. return;
  68. }
  69. }

5.2 创建目录

  1. /**
  2. * @brief 辅助函数 主要用于探测一下文件是否存在
  3. * @param[in] file 文件名称
  4. * @param[out] st 更新当前文件信息
  5. * @return 返回执行结果
  6. */
  7. static int __lstst(const char *file, struct stat *st = nullptr)
  8. {
  9. struct stat new_st;
  10. int ret = lstat(file, &new_st);
  11. if(st)
  12. *st = new_st;
  13. return ret;
  14. }
  15. /**
  16. * @brief 创建目录的辅助函数
  17. * @param[in] dirname 目录名称
  18. * @return 返回创建目录的结果
  19. */
  20. static int __mkdir(const char* dirname)
  21. {
  22. //该目录已经存在 不需要再创建
  23. if(access(dirname, F_OK) == 0)
  24. return 0;
  25. return mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  26. }
  27. /**
  28. * @brief 创建一个目录
  29. * @param[in] dirname 目录名称
  30. * @return 返回是否成功创建了目录
  31. */
  32. bool FSUtil::Mkdir(const std::string& dirname)
  33. {
  34. //目录已经存在
  35. if(__lstst(dirname.c_str()) == 0)
  36. return true;
  37. //给目录名称进行深拷贝
  38. char *path = strdup(dirname.c_str());
  39. if(!path)
  40. {
  41. KIT_LOG_ERROR(g_logger) << "strdup mem is not enough! errno=" << errno << ", is:" << strerror(errno);
  42. return false;
  43. }
  44. char *ptr = strchr(path + 1, '/');
  45. if(!ptr)
  46. {
  47. KIT_LOG_ERROR(g_logger) << "strchr: no find '/' invalid dirname!";
  48. return false;
  49. }
  50. //如果存在多级目录 逐级检查是否存在 不存在就会创建
  51. for(;ptr; *ptr = '/', ptr = strchr(ptr + 1, '/'))
  52. {
  53. //截断到当前层的目录路径
  54. *ptr = '\0';
  55. //检查是否存在 不存在就创建 创建失败就退出
  56. if(__mkdir(path) != 0)
  57. break;
  58. }
  59. //找完了最后的'/' 尝试最后一层目录是否存在
  60. if(ptr == nullptr)
  61. {
  62. if(__mkdir(path) == 0)
  63. {
  64. free(path);
  65. return true;
  66. }
  67. }
  68. free(path);
  69. return false;
  70. }

6. 单例模板封装

来自**single.h**文件
目的:将我们指定的类封装为一个单例对象来使用。

  1. template<class T, class X = void, int N = 0>
  2. class Single
  3. {
  4. public:
  5. static T* GetInstance()
  6. {
  7. static T v;//C++11 魔力static 保证线程安全
  8. return &v;
  9. }
  10. };
  11. template<class T, class X = void, int N = 0>
  12. class SinglePtr
  13. {
  14. public:
  15. static std::shared_ptr<T> GetInstance()
  16. {
  17. static std::shared_ptr<T> v(new T);
  18. return v;
  19. }
  20. };