(10)muduo_base库源码分析:Timestamp.cc和Timestamp.h

时间:2022-03-16 00:52:42


文章目录

  • ​​1.Timestamp.h的研究​​
  • ​​2.Timestamp.cc的研究​​
  • ​​2.相关测试代码​​

1.Timestamp.h的研究

  • Timestamp类图如下,参考下即可
  • 位置:muduo\base\Timestamp.h
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef MUDUO_BASE_TIMESTAMP_H
#define MUDUO_BASE_TIMESTAMP_H

#include "muduo/base/copyable.h"
#include "muduo/base/Types.h"

#include <boost/operators.hpp>


//
namespace muduo
{

///
/// Time stamp in UTC, in microseconds resolution.
///
/// This class is immutable.
/// It's recommended to pass it by value, since it's passed in register on x64.
///
/*
muduo:copyable表示空基类,标识类,值类型
值语义:可以拷贝的,拷贝之后,与原对象脱离关系
对象语义:要么是不能拷贝的,要么是可以拷贝的,拷贝之后与原对象仍然存在一定的关系,比如共享底层资源(要实现自己的拷贝构造函数)
muduo大部分都是对象语义
*/

class Timestamp : public muduo::copyable,
public boost::equality_comparable<Timestamp>,
public boost::less_than_comparable<Timestamp>
{
public:
///
/// Constucts an invalid Timestamp.
///
Timestamp()
: microSecondsSinceEpoch_(0)
{
}

///
/// Constucts a Timestamp at specific time
///
/// @param microSecondsSinceEpoch
explicit Timestamp(int64_t microSecondsSinceEpochArg)
: microSecondsSinceEpoch_(microSecondsSinceEpochArg)
{
}

void swap(Timestamp& that)
{
//形参引用的改变能影响到实参,因为这里是引用
std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);
}

// default copy/assignment/dtor are Okay

string toString() const;
string toFormattedString(bool showMicroseconds = true) const;

bool valid() const { return microSecondsSinceEpoch_ > 0; }

// for internal usage.
int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; }
time_t secondsSinceEpoch() const
{ return static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); }

///
/// Get time of now.
///
static Timestamp now();
static Timestamp invalid()
{
return Timestamp();
}


static Timestamp fromUnixTime(time_t t)
{
return fromUnixTime(t, 0);
}

static Timestamp fromUnixTime(time_t t, int microseconds)
{
return Timestamp(static_cast<int64_t>(t) * kMicroSecondsPerSecond + microseconds);
}

static const int kMicroSecondsPerSecond = 1000 * 1000;

private:
int64_t microSecondsSinceEpoch_;
};

//equality_comparable和less_than_comparable的模板元的原因,要求实现<,可自动实现>,<=,>=

inline bool operator<(Timestamp lhs, Timestamp rhs)
{
return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch();
}

inline bool operator==(Timestamp lhs, Timestamp rhs)
{
return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch();
}

///
/// Gets time difference of two timestamps, result in seconds.
///
/// @param high, low
/// @return (high-low) in seconds
/// @c double has 52-bit precision, enough for one-microsecond
/// resolution for next 100 years.
//1us=百万分之1s,两个微s相减/1000000,单位成为秒
inline double timeDifference(Timestamp high, Timestamp low)
{
int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch();
return static_cast<double>(diff) / Timestamp::kMicroSecondsPerSecond;
}

///
/// Add @c seconds to given timestamp.
///
/// @return timestamp+seconds as Timestamp
///
inline Timestamp addTime(Timestamp timestamp, double seconds)
{
int64_t delta = static_cast<int64_t>(seconds * Timestamp::kMicroSecondsPerSecond);
return Timestamp(timestamp.microSecondsSinceEpoch() + delta);
}

} // namespace muduo

#endif // MUDUO_BASE_TIMESTAMP_H

2.Timestamp.cc的研究

  • 位置:muduo\base\Timestamp.cc
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include "muduo/base/Timestamp.h"

#include <sys/time.h>
#include <stdio.h>

//用于宏PRId64能用
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#include <inttypes.h>

using namespace muduo;

static_assert(sizeof(Timestamp) == sizeof(int64_t),
"Timestamp is same size as int64_t");

string Timestamp::toString() const
{
char buf[32] = {0};
int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;

/*
int64_t用来表示64位整数,在32位系统中是long long int,在64位系统中是long int,所以打印int64_t的格式化方法是:
printf(“%ld”, value); // 64bit OS
printf("%lld", value); // 32bit OS

跨平台的做法:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#undef __STDC_FORMAT_MACROS
printf("%" PRId64 "\n", value);
*/
//PRId64用于跨平台的,from:<inttypes.h>,若是64bit的,就等于ld,若是32bit的,就等于lld
snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
return buf;
}

string Timestamp::toFormattedString(bool showMicroseconds) const
{
char buf[64] = {0};
//求出距离1970.1.1的秒数
time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
struct tm tm_time;
gmtime_r(&seconds, &tm_time);//_r表示线程,可以将秒数转换为tm_time结构体

if (showMicroseconds)
{
int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);//转换成微妙数
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);
}
else
{
snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d",
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);
}
return buf;
}

//获取当前时间
Timestamp Timestamp::now()
{
struct timeval tv;
gettimeofday(&tv, NULL);//gettimeofday(,时区),NULL表示没有时区
int64_t seconds = tv.tv_sec;//表示tv.tv_sec秒
return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);//tv.tv_usec表示微妙
}

2.相关测试代码

  • 目录结构
    (1)将muduo库下的build以及CMakeLists.txt拷贝至jmuduo目录下;
    (2)将muduo-master/muduo/base下的CMakeLists.txt,copyable.h,Timestamp.cc,Timestamp.h,Types.h拷贝到jmuduo/jmuduo/base下面;
修改后的内容如下:
===================================10\jmuduo\muduo\base\CMakeLists.txt=================================================
set(base_SRCS
Timestamp.cc
)##相当于:base_SRCS=Timestamp.cc

add_library(muduo_base ${base_SRCS}) ##将base_SRCS的文件生成为muduo_base的库
target_link_libraries(muduo_base pthread rt)##需要链接pthread库和rt库

install(TARGETS muduo_base DESTINATION lib)
file(GLOB HEADERS "*.h")
install(FILES ${HEADERS} DESTINATION include/muduo/base)

if(NOT CMAKE_BUILD_NO_EXAMPLES)
add_subdirectory(tests)
endif()
  • 测试BOOST_STATIC_ASSERT运行时的断言相关代码,assert是运行时的断言
    (1)在jmuduo/tests/下添加:bsa.cc以及CMakeLists.txt文件;
    (2)此外还需要在jmuduo/CMakeLists.txt下添加:add_subdirectory(tests);
    (3)直接在jmuduo下面,运行./build即可
===========================================10\jmuduo\tests\bsa.cc=======================================================
#include <boost/static_assert.hpp>

class Timestamp
{
private:
int64_t microSecondsSinceEpoch_;
};

//编译时的断言,来自boost库,assert是运行时的断言
BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t));//在编译的时候不会出错
//BOOST_STATIC_ASSERT(sizeof(int) == sizeof(short));//在编译的时候会出错

int main(void)
{
return 0;
}

======================================10\jmuduo\tests\CMakeLists.txt===============================================
add_executable(bsa bsa.cc)


========================================10\jmuduo\CMakeLists.txt=================================================

。。。。。
,,,,,
。。。。
add_subdirectory(tests)##这里是为了编译tests文件夹下的bsa.cc和Cmake文件
  • 测试imestamp_unittest.cc。来自muduo\base\tests\Timestamp_unittest.cc
    (1)将muduo的Timestamp_unittest.cc拷贝至10\jmuduo\muduo\base\tests\Timestamp_unittest.cc
    (2)在10\jmuduo\muduo\base\tests\目录下添加:CMakeLists.txt
    (3)在10\jmuduo\下,执行build.sh
==================================10\jmuduo\muduo\base\tests\CMakeLists.txt===================
add_executable(timestamp_unittest Timestamp_unittest.cc)##可执行文件是:timestamp_unittest
target_link_libraries(timestamp_unittest muduo_base)##需要链接muduo_base库

================================10\jmuduo\muduo\base\tests\Timestamp_unittest.cc代码解释如下:=======================
#include "muduo/base/Timestamp.h"
#include <vector>
#include <stdio.h>

using muduo::Timestamp;

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

void passByValue(Timestamp x)
{
printf("%s\n", x.toString().c_str());
}

void benchmark()
{
const int kNumber = 1000*1000;//const常量加个k,这是google的编码规范

std::vector<Timestamp> stamps;
stamps.reserve(kNumber);//预留了能容纳100万个Timestamp的空间
for (int i = 0; i < kNumber; ++i)
{
//插入100万个时间
stamps.push_back(Timestamp::now());//这里消耗的时间主要是now函数的gettimeofday,push_bak已经预留了空间,所以不会消耗时间
}
printf("%s\n", stamps.front().toString().c_str());
printf("%s\n", stamps.back().toString().c_str());
printf("%f\n", timeDifference(stamps.back(), stamps.front()));//计算最后一个时间和第一个时间的时间差

int increments[100] = { 0 };
int64_t start = stamps.front().microSecondsSinceEpoch();//相当于下标为0的时间
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 %d\n", static_cast<int>(inc));
}
}

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

int main()
{
//调用拷贝构造函数:用一个对象初始化另一个对象
//Timestamp::now()是没有名称的对象,所以将其构造函数的值拷贝给now对象,看now里面的return代码就明白了!!
Timestamp now(Timestamp::now());//等价于:Timestamp now=Timestamp::now()
printf("%s\n", now.toString().c_str());
passByValue(now);//值传递
passByConstReference(now);//引用传递
benchmark();//这是个基准函数
}
  • 结果展示:
代码位置:可以参考下,
wangji/src/10/build/debug/bin$ ./timestamp_unittest

(10)muduo_base库源码分析:Timestamp.cc和Timestamp.h

  • 其它文件:10\jmuduo\build.sh,10\jmuduo\CMakeLists.txt
===================================10\jmuduo\build.sh==========================
#!/bin/sh

set -x

SOURCE_DIR=`pwd`
BUILD_DIR=${BUILD_DIR:-../build}
BUILD_TYPE=${BUILD_TYPE:-debug}
INSTALL_DIR=${INSTALL_DIR:-../${BUILD_TYPE}-install}
BUILD_NO_EXAMPLES=${BUILD_NO_EXAMPLES:-0}

mkdir -p $BUILD_DIR/$BUILD_TYPE \
&& cd $BUILD_DIR/$BUILD_TYPE \
&& cmake --graphviz=dep.dot \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \
-DCMAKE_BUILD_NO_EXAMPLES=$BUILD_NO_EXAMPLES \
$SOURCE_DIR \
&& make $*

cd $SOURCE_DIR && doxygen


==================================10\jmuduo\CMakeLists.txt==================================
cmake_minimum_required(VERSION 2.6)

project(muduo CXX)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()

set(CXX_FLAGS
-g
# -DVALGRIND
# -DMUDUO_STD_STRING
-D_FILE_OFFSET_BITS=64
-Wall
-Wextra
-Werror
-Wconversion
-Wno-unused-parameter
-Wold-style-cast
-Woverloaded-virtual
-Wpointer-arith
-Wshadow
-Wwrite-strings
-march=native
# -MMD
# -std=c++0x
-rdynamic
)
if(CMAKE_BUILD_BITS EQUAL 32)
list(APPEND CXX_FLAGS "-m32")
endif()
string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}")

set(CMAKE_CXX_COMPILER "g++")
#set(CMAKE_CXX_COMPILER "icpc")
set(CMAKE_CXX_FLAGS_DEBUG "-O0")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -finline-limit=1000 -DNDEBUG")
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

find_package(Boost REQUIRED)
find_package(Protobuf)
find_package(CURL)
find_path(CARES_INCLUDE_DIR ares.h)
find_library(CARES_LIBRARY NAMES cares)
find_path(MHD_INCLUDE_DIR microhttpd.h)
find_library(MHD_LIBRARY NAMES microhttpd)
find_library(BOOSTTEST_LIBRARY NAMES boost_unit_test_framework)

include_directories(${Boost_INCLUDE_DIRS})

include_directories(${PROJECT_SOURCE_DIR})

string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE)
message(STATUS "CXX_FLAGS = " ${CMAKE_CXX_FLAGS} " " ${CMAKE_CXX_FLAGS_${BUILD_TYPE}})

add_subdirectory(muduo/base) ##添加编译子目录
#add_subdirectory(muduo/net)

###下面是muduo的examples,目前还没,所以注释了
#if(NOT CMAKE_BUILD_NO_EXAMPLES)
# add_subdirectory(examples)
#else()
# if(CARES_INCLUDE_DIR AND CARES_LIBRARY)
# add_subdirectory(examples/cdns)
# endif()
#endif()

add_subdirectory(tests)##这里是为了编译tests文件夹下的bsa.cc和Cmake文件