zoukankan      html  css  js  c++  java
  • muduo_base 01 (Timestamp)

    备份自Github pages muduo_base 01 (Timestamp) pusidun's blog

    本文源码基于muduo v2.0.2分析

    类图

    通读源码之前的几点说明

    class Timestamp : public muduo::copyable,
                      public boost::equality_comparable<Timestamp>,
                      public boost::less_than_comparable<Timestamp>
    

    Timestamp继承的3个基类,下面将分别介绍

    copyable & nocopyable

    值语义:可以拷贝,拷贝之后与原对象脱离关系

    对象语义:要么不能拷贝,要么可以拷贝,拷贝之后与原对象仍然有联系,比如共享底层资源(要实现自己的拷贝构造函数)

    class copyable
    {
     protected:
      copyable() = default;
      ~copyable() = default;
    };
    
    class noncopyable
    {
     public:
      noncopyable(const noncopyable&) = delete;
      void operator=(const noncopyable&) = delete;
    
     protected:
      noncopyable() = default;
      ~noncopyable() = default;
    };
    

    equality_comparable & less_than_comparable

    头文件boost/operators.hpp

    要派生自 boost::less_than_comparable, 派生类(T)必须提供:

    bool operator<(const T&, const T&);

    less_than_comparable 将依照 operator< 实现其余的三个操作符

    bool operator>(const T&,const T&);
    bool operator<=(const T&,const T&);
    bool operator>=(const T&,const T&);
    

    同理,要派生自 boost::equality_comparable, 派生类(T)必须提供:

    bool operator==(const T&,const T&);

    将自动完成bool operator!=(const T&,const T&);

    静态断言static_assert

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

    编译时断言,条件为true不打印信息,false时打印

    多平台PRid64占位

    snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
    

    64位类型的printf占位符是ld,而32位是lld。为适应32位和64位的系统,使用了PRId64

    PRId64位于头文件inttypes.h

    # if __WORDSIZE == 64
    #  define __PRI64_PREFIX	"l"
    # else
    #  define __PRI64_PREFIX	"ll"
    # endif
    
    # define PRId64		__PRI64_PREFIX "d"
    

    同时,inttypes头文件可能需要定义宏__STDC_FORMAT_MACROS后才能include,具体根据编译器

    #ifndef __STDC_FORMAT_MACROS
    #define __STDC_FORMAT_MACROS
    #include <inttypes.h>
    #undef __STDC_FORMAT_MACROS
    #endif
    

    stackoverflow 讨论

    通读源码

    Timestamp整体实现比较简单。从静态函数now()开始看起,其余函数围绕now得到的时间,进行格式化输出等操作。

    Timestamp Timestamp::now()
    {
      struct timeval tv;
      gettimeofday(&tv, NULL);
      int64_t seconds = tv.tv_sec;
      return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
    }
    

    gettimeofday原型

    #include <sys/time.h>
    
    int gettimeofday(struct timeval *restrict tv,
                    struct timezone *restrict tz);
    int settimeofday(const struct timeval *tv,
                    const struct timezone *tz);
    /*
    struct timeval {
            time_t      tv_sec;     /* seconds */
            suseconds_t tv_usec;    /* microseconds */
        };
    struct timezone {
            int tz_minuteswest;     /* minutes west of Greenwich */
            int tz_dsttime;         /* type of DST correction */
        };
    
    @ret: return 0 for success.On error, -1 is returned and errno is set to indicate the error.
    */
    
    

    gettimeofday是C库提供的函数,其封装了sys_gettimeofday系统调用。但在x64结构上,gettimeofday可以不通过系统调用拿到系统时间。先看2个概念:

    1. 墙上时间:即实际时间(1970/1/1号以来的时间),它是由我们主板电池供电的(装过PC机的同学都了解)RTC单元存储的,这样即使机器断电了时间也不用重设。当操作系统启动时,会用这个RTC来初始化墙上时间,接着,内核会在一定精度内根据jiffies维护这个墙上时间。

    2. jiffies:就是操作系统启动后经过的时间,它的单位是节拍数。有些体系架构,1个节拍数是10ms,但我们常用的x86体系下,1个节拍数是1ms。也就是说,jiffies这个全局变量存储了操作系统启动以来共经历了多少毫秒。

    x64下do_gettimeofday

    void do_gettimeofday(struct timeval *tv)
    {
    	unsigned long seq, t;
     	unsigned int sec, usec;
     
    	do {
    		seq = read_seqbegin(&xtime_lock);
     
    		sec = xtime.tv_sec;
    		usec = xtime.tv_nsec / 1000;
    		t = (jiffies - wall_jiffies) * (1000000L / HZ) +
    			do_gettimeoffset();
    		usec += t;
     
    	} while (read_seqretry(&xtime_lock, seq));
     
    	tv->tv_sec = sec + usec / 1000000;
    	tv->tv_usec = usec % 1000000;
    }
    

    可以看出是通过xtime和jiffies共同得出的tv,没有经过系统调用。
    更多的讨论请看浅谈时间函数gettimeofday的成本-陶辉

    其他函数不再讨论

    unittest代码

    benchmark部分:

    调用Timestamp::now()填充一个大小为1M的std::vector,并且打印出小于100ms的延迟分布情况

  • 相关阅读:
    《软件项目成功之道》阅读笔记02
    每日日报47
    每日日报46
    每日日报45
    WAMPSERVER打开phpmyadmin时遇到404错误——解决办法
    每日日报44
    每日日报43
    简单的利用Layui来实现登录功能
    01函数式编程概念
    03适配器模式
  • 原文地址:https://www.cnblogs.com/pusidun/p/14836844.html
Copyright © 2011-2022 走看看