/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里面,提供了两个类型转换的函数
隐式转换和向下转换
template3 GCC的CASinline 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); }
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::AtomicIntegerT4 Exception 类实现AtomicInt32; typedef detail::AtomicIntegerT AtomicInt64; // 32 64位整数
用于保存栈帧地址
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 }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)