1 muduo网络库的目录结构和代码实现细节

1 muduo网络库的目录结构和代码实现细节,第1张

1 muduo网络库的目录结构和代码实现细节 1 muduo网络库的目录结构
/muduo$ tree ./ -L 2
./
├── BUILD.bazel
├── build.sh
├── ChangeLog
├── ChangeLog2
├── CMakeLists.txt
├── contrib
│?? ├── CMakeLists.txt
│?? ├── hiredis
│?? └── thrift
├── muduo
├── README
└── WORKSPACE
……

muduo库主体代码

├── muduo
│   ├── base
# base与网络无关的基础代码,包括线程库::muduo namespace 
# ::muduo::net namespace 
│   └── net
        ├── inspect
            ├── poller
            ├── http
            ├── protobuf
            ├── protorpc
# 关于网络模块和rpc的代码

base目录

chen@ecs-213609:~/muduo/muduo/base$ tree ./ -L 1
./
├── AsyncLogging.cc	# 异步的日志
├── AsyncLogging.h
├── Atomic.h		# 原子 *** 作
├── BlockingQueue.h	# 无阻塞队列
├── BoundedBlockingQueue.h
├── BUILD.bazel
├── CMakeLists.txt
├── Condition.cc		# 条件变量
├── Condition.h
├── copyable.h			# 默认可以拷贝的类,空基类
├── CountDownLatch.cc 	# 倒计时门闩同步作用
├── CountDownLatch.h	
├── CurrentThread.cc	# 线程
├── CurrentThread.h
├── Date.cc		
├── Date.h
├── Exception.cc
├── Exception.h
├── FileUtil.cc
├── FileUtil.h
├── GzipFile.h			# 压缩文件
├── LogFile.cc			# 日志文件等
├── LogFile.h		
├── Logging.cc
├── Logging.h
├── LogStream.cc
├── LogStream.h
├── Mutex.h				# 互斥
├── noncopyable.h
├── ProcessInfo.cc
├── ProcessInfo.h
├── Singleton.h
├── StringPiece.h
├── tests
├── Thread.cc
├── Thread.h
├── ThreadLocal.h
├── ThreadLocalSingleton.h
├── ThreadPool.cc	# 线程池
├── ThreadPool.h
├── Timestamp.cc
├── Timestamp.h
├── TimeZone.cc
├── TimeZone.h
├── Types.h
└── WeakCallback.h

base都是可以提取出来直接使用的一些工具类

base/tests下是一些测试用例

执行./build.sh会在上层目录生成一个build/Debug目录

有需要可以把shell脚本给改掉

set -x

SOURCE_DIR=`pwd`
BUILD_DIR=${BUILD_DIR:-./build}
BUILD_NO_EXAMPLES=${BUILD_NO_EXAMPLES:-0}

mkdir -p $BUILD_DIR/$BUILD_TYPE 
  && cd $BUILD_DIR/$BUILD_TYPE 
  && cmake $SOURCE_DIR 
  && make $*
rm CMakeCache.txt
rm CMakeFiles -r 
rm cmake_install.cmake

删掉一些冗余文件和Debug目录的一些信息,只做最简单的应用输出

build/release-cpp11/bin下会生成可执行文件

tree ./ -L 1
./
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── dep.dot
├── dep.dot.muduo_base
├── dep.dot.muduo_base.dependers
├── lib
├── Makefile
└── muduo

单独编译Timestamp.cc会生成muduo_base静态库

set(base_SRCS
  Timestamp.cc
  )

add_library(muduo_base ${base_SRCS})
target_link_libraries(muduo_base pthread rt)

install(TARGETS muduo_base DESTINATION lib)
file(GLOB HEADERS "*.h")
install(FILES ${HEADERS} DESTINATION include/muduo/base)
2 Timestamp时间处理

copyable.h //默认可以拷贝的类,空基类,值语义

#ifndef MUDUO_base_COPYABLE_H
#define MUDUO_base_COPYABLE_H
namespace muduo {
class copyable {
 protected:
  copyable() = default;
  ~copyable() = default;
};
} 
#endif  // MUDUO_base_COPYABLE_H                    

比如 Timestamp 类 处理时间的

class Timestamp : public muduo::copyable,
                  public boost::less_than_comparable
{
   inline bool operator<(Timestamp lhs, Timestamp rhs)
    {
      return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch();
    }                   
}

继承了该类,要求实现了<,可以自动实现>,<=,>= 的运算符重载,模板元编程的思想。

static const int muduo::Timestamp::microSecondsSinceEpoch_ 
priavte : int64_t muduo::Timestamp::kMicroSecondsPerSecond 
    
    
muduo::Timestamp::valid muduo::Timestamp::toString()const
muduo::Timestamp::toFormattedString() const
muduo::Timestamp::Timestamp muduo::Timestamp::Timestamp()
muduo::Timestamp::swap muduo::Timestamp::secondsSinceEpoch()const
muduo::Timestamp::now()
muduo::Timestamp(int64_t microSecondsSinceEpoch)
muduo::Timestamp::invalid()
void swap(Timestamp& that)
  {
    std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);
  }
// 用于交换两个时间戳,&引用传递
inline double timeDifference(Timestamp high, Timestamp low)
// 返回时间戳的微秒数
    
inline Timestamp addTime(Timestamp timestamp, double seconds)
// 两个时间戳相加
Timestamp Timestamp::now()
// 距离1970年的微秒数
string Timestamp::toString() const
{
      // 乘以100W,得到微秒数,用一个结构体tm_time来获取当前距离1970年经过的秒数
      char buf[32] = {0};
      time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
      int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
      struct tm tm_time;
      gmtime_r(&seconds, &tm_time); // 线程安全函数

      snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
          tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
          tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
          microseconds);
    // 拼接到buf里面,获取当前的年月日,时分秒,微妙
  return buf;

}

toString()

string Timestamp::toString() const
{
  // int64_t PRId64用来表示64位整数,跨平台的打印法是PRld64
  char buf[32] = {0};
  int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
  int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
  snprintf(buf, sizeof(buf)-1, "%"  ".%06" PRId64 "", seconds, microseconds);
  return buf;
}

Timestamp_unittest.cc

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using muduo::Timestamp;

void passByConstReference(const Timestamp& x)
{
  printf("%sn", x.toString().c_str());
}

void passByValue(Timestamp x)
{
    int a = 0;
    printf("%sn", x.toString().c_str());
}

void benchmark()
{
  const int kNumber = 1000*1000;

  std::vector stamps;
  stamps.reserve(kNumber);  // 预分配空间,100万个对象空间
  for (int i = 0; i < kNumber; ++i)
  {
    // 一百万个时间对象,now静态函数 系统调用计算微妙的
    stamps.push_back(Timestamp::now());
  }
  printf("%sn", stamps.front().toString().c_str());
  printf("%sn", stamps.back().toString().c_str());
  // 计算一百万次的时间差
  printf("%fn", timeDifference(stamps.back(), stamps.front()));

  int increments[100] = { 0 };
  int64_t start = stamps.front().microSecondsSinceEpoch(); // 第一个时间的微秒数
  for (int i = 1; i < kNumber; ++i)
  {
    int64_t next = stamps[i].microSecondsSinceEpoch();    // 相近两个时间的时间差
    int64_t inc = next - start;
    start = next;
    if (inc < 0)          
    {
      // 时间逆转了,一般不可能出现这种问题
      printf("reverse!n");
    }
    else if (inc < 100)
    {
      ++increments[inc]; // 有几个时间差是小于100
    }
    else
    {
      printf("big gap %dn", static_cast(inc));
      // 大于一百微妙的时间差 
    }
  }

  for (int i = 0; i < 100; ++i)
  {
    printf("%2d: %dn", i, increments[i]);
  }
}

int main()
{
  Timestamp now(Timestamp::now());
  printf("%sn", now.toString().c_str()); // 输出当前时间
  passByValue(now);
  passByConstReference(now);
  benchmark(); // 度量时间的函数
}

在包含的type.h里面,提供了两个类型转换的函数

隐式转换和向下转换

template
inline To implicit_cast(From const &f) {
  return f;
}
template     
inline To down_cast(From* f) {
     if (false) {
    implicit_cast(0);
  }
#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) // 判断运行时类型识别才能转型RTTI
  assert(f == NULL || dynamic_cast(f) != NULL);  // c++类型转换,专门父类转子类的运算符,前提是基类指针指向派生类对象才能
#endif
  return static_cast(f);
}
3 GCC的CAS

GCC4.1+版本中支持CAS的原子 *** 作(完整的原子 *** 作可参看 GCC Atomic Builtins)

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, …)

type __sync_val_compare_and_swap (type *ptr, type oldval type newval, …)

AtomicIntegerT一个整数得原子性 *** 作

volatile T value_ 系统总是重新从它所在得内存读取数据,而不是使用保存在寄存器中得备份。即使他前一条指令刚刚读取过数据被保存。防止编译器对该 *** 作优化,需要每次精准读值。

T get()
  {
    return __sync_val_compare_and_swap(&value_, 0, 0);
    // 比较一下当前value_得值是否为0,返回value_修改之前得值
  }
T getAndAdd(T x)
  {
    return __sync_fetch_and_add(&value_, x);
    // 返回没有修改得值,再把value_+x
  }
T incrementAndGet()
  {
    return addAndGet(1);
	// 自加+  
  }
T getAndSet(T newValue)
  {
    return __sync_lock_test_and_set(&value_, newValue);
    // 返回原来得值,再获取新的值
  }
typedef detail::AtomicIntegerT AtomicInt32;
typedef detail::AtomicIntegerT AtomicInt64;
// 32 64位整数
4 Exception 类实现

用于保存栈帧地址

Exception::Exception(const char* msg)
  : message_(msg)
{
  fillStackTrace();
}
void Exception::fillStackTrace()
{
  const int len = 200;
  void* buffer[len];
  int nptrs = ::backtrace(buffer, len); // man 3 是个把调用信息返回的函数,当前程序活动中的程序调用,返回到buffer里面
  char** strings = ::backtrace_symbols(buffer, nptrs);
    //对应返回task frame的解析,将地址转换成函数符号,二级指针,指向了一个指针数组
  if (strings)
  {
    for (int i = 0; i < nptrs; ++i)
    {
      
      stack_.append(strings[i]);
      stack_.push_back('n');
    }
    free(strings);
  }
}

Exception_test.cc使用实例

能够把异常的调用堆栈打印出来

int main()
{
  try
  {
    foo();
  }
  catch (const muduo::Exception& ex)
  {
    printf("reason: %sn", ex.what());
    printf("stack trace: %sn", ex.stackTrace());
  }
}

5 Thread类的一些细节

thread_test.cc

int main()
{
  printf("pid=%d, tid=%dn", ::getpid(), muduo::CurrentThread::tid());
}

打印当前工作线程的时候

CurrentThread::tid()

// ……
extern __thread int t_cachedTid; // 线程局部存储
// ……
inline int tid()
  {
    if (t_cachedTid == 0)
    {
      cacheTid(); // 如果已经获取过缓存就不会再获取,而是直接返回,减少系统调用
    }
    return t_cachedTid;
  }
void CurrentThread::cacheTid()
{
  if (t_cachedTid == 0)
  {
    t_cachedTid = detail::gettid();
    int n = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
    assert(n == 6); (void) n; 
      // 由于n是编译时断言,加上(void),防止release verison因为该变量没有使用而出现警告
  }
}

pid_t gettid()

pid_t gettid()
{
  return static_cast(::syscall(SYS_gettid));
    // 调用系统调用获取真实的tid
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5690436.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存