muduo CurrentThread 解析

本文介绍C++中的几种优化技巧,包括使用__builtin_expect减少跳转次数、高效获取线程ID、利用__thread实现线程局部存储、实现微秒级休眠、通过extern声明与定义分离以及如何获取和解析栈跟踪等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

丧心病狂的C++优化

  inline int tid()
  {
    if (__builtin_expect(t_cachedTid == 0, 0))
    {
      cacheTid();
    }
    return t_cachedTid;
  }

__builtin_expect 宏 的作用:
其实__builtin_expect这个宏定义变量本身的值是没有产生影响的。它的主要作用是在汇编层优化我们代码,减少跳转的次数。在C语言中,if(a){printf(“1”);else{printf(“0”);}}。假设程序员知道a很有可能是True,为了提高效率,就增加 __builtin_expect。写成
if( __builtin_expect(!!(x),1))
那么编译器在汇编时会把printf(“1”);放在jmp语句的下面,这样就节省了效率。
总结来说 __builtin_except 就是对 if else 语句的优化。

获得 tid

#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
int main(int argc,const char *argv[]){

        long pid = syscall(SYS_gettid);
        printf("pid = [%lu]\n",pid);
        return 0;
}

调用系统函数,高效获得线程id;

__thread 线程变量

__thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。
简单来说,就是每个用该修饰符修饰的变量在每个线程中都会有存在。

微秒级别的时间sleep

void CurrentThread::sleepUsec(int64_t usec)
{
	struct timespec ts = { 0, 0 };
	ts.tv_sec = static_cast<time_t>(usec / Timestamp::kMicroSecondsPerSecond);
	ts.tv_nsec = static_cast<long>(usec % Timestamp::kMicroSecondsPerSecond * 1000);
	::nanosleep(&ts, NULL);
}

extern 使用

声明在 .h 文件
定义在 .cc 文件
有待理解

stacktrace

#include <execinfo.h>

int backtrace(void **buffer, int size);

char **backtrace_symbols(void *const *buffer, int size);

void backtrace_symbols_fd(void *const *buffer, int size, int fd);

(1)int backtrace (void **buffer, int size);

该函数用来获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针数组。参数size用来指定buffer中可以保存多少个void* 元素。函数返回值是实际获取的指针个数,最大不超过size大小在buffer中的指针实际是从堆栈中获取的返回地址,每一个堆栈框架有一个返回地址。注意某些编译器的优化选项对获取正确的调用堆栈有干扰,另外内联函数没有堆栈框架;删除框架指针也会使无法正确解析堆栈内容。

(2)char **backtrace_symbols (void *const *buffer, int size);

该函数将从backtrace函数获取的信息转化为一个字符串数组。参数buffer是从backtrace函数获取的数组指针,size是该数组中的元素个数(backtrace的返回值),函数返回值是一个指向字符串数组的指针,它的大小同buffer相同。每个字符串包含了一个相对于buffer中对应元素的可打印信息。它包括函数名,函数的偏移地址和实际的返回地址。backtrace_symbols生成的字符串都是malloc出来的,但是不要最后一个一个的free,因为backtrace_symbols会根据backtrace给出的callstack层数,一次性的将malloc出来一块内存释放,所以,只需要在最后free返回指针就OK了。

(3)void backtrace_symbols_fd (void *const *buffer, int size, int fd);

该函数与backtrace_symbols函数具有相同的功能,不同的是它不会给调用者返回字符串数组,而是将结果写入文件描述符为fd的文件中,每个函数对应一行。它不需要调用malloc函数,因此适用于有可能调用该函数会失败的情况。

backtrace将当前程序的调用信息存储在buffer中,backtrace_symbols则是将buffer翻译为字符串。后者用到了malloc,所以需要手工释放内存。

// 栈痕迹
// 将C++ ABI标识符(C++ ABI identifier)转换成C++源程序标识符
// (original C++ source identifier)的过程称为demangle。
string stackTrace(bool demangle)
{
  string stack;
  const int max_frames = 200;
  // frame 指针, 指针类型为 void *
  void* frame[max_frames];
  int nptrs = ::backtrace(frame, max_frames);
  // 返回值是 malloc 出来的,但是是一块完整内存块,使用free释放
  char** strings = ::backtrace_symbols(frame, nptrs);
  if (strings)
  {
    size_t len = 256;
    // demangled 在 demangle 为 false 时 赋值为 nullptr
    char* demangled = demangle ? static_cast<char*>(::malloc(len)) : nullptr;
    for (int i = 1; i < nptrs; ++i)  // skipping the 0-th, which is this function
    {
      if (demangle)
      {
        // https://panthema.net/2008/0901-stacktrace-demangled/
        // bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909]
        char* left_par = nullptr;
        char* plus = nullptr;
        for (char* p = strings[i]; *p; ++p)
        {
          if (*p == '(')
            left_par = p;
          else if (*p == '+')
            plus = p;
        }

        if (left_par && plus)
        {
          *plus = '\0';
          int status = 0;
          char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status);
          *plus = '+';
          if (status == 0)
          {
            demangled = ret;  // ret could be realloc()
            stack.append(strings[i], left_par+1);
            stack.append(demangled);
            stack.append(plus);
            stack.push_back('\n');
            continue;
          }
        }
      }
      // Fallback to mangled names
      stack.append(strings[i]);
      stack.push_back('\n');
    }
    free(demangled);
    free(strings);
  }
  return stack;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值