/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::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
}



