muduo base库系列一:时间戳、线程类

参考自:b站视频
https://www.bilibili.com/video/BV1Zt411K7Gg?spm_id_from=333.999.0.0

timestamp时间戳

类图:
在这里插入图片描述
封装了unix时钟值,且可以调用类方法转换成xx年xx月xx日的形式,用于日志记录时的时间标识。

以下是一些实现细节:

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

copyable是一个用于标识当前类可以拷贝的类,继承它就意味着当前类可以拷贝。也就是实现了值语义(也就是可以拷贝,拷贝之后的值与原来的值没有关系;与之相反的是对象语义,要么不能拷贝,要么拷贝之后与原对象仍有关系,比如指针的拷贝)。
equality_comparable和less_than_comparable是两个模板类,继承前者可以自动实现类型比较函数(重载==号),继承后者的话,只要自己重载<号,就可以自动重载<、<=、>=。

Atomic原子操作

原子操作是指这个操作在执行过程中不会被其他打断。原子操作的粒度比锁更细,适用于某个变量的读写,c++11后,标准库也支持原子类型。

volatile关键字:
用volatile修饰变量的时候,系统总会从变量所在的内存读取数据,而不会读取它在寄存器中的吧备份。
volatile本质上是避免某些指令在编译过程中被优化掉。可以做到两件事:1、阻止编译器为了提高效率把一个变量缓存到寄存器而不写回内存。2、阻止编译器调整volatile变量的指令顺序。

Execption异常

主要实现了stackTrace,也就是保存了函数栈,发生异常的时候可以输出栈帧的情况,以便于了解哪个函数调用出现了异常。
内部调用了backtarce和backtrace_symbols函数保存了栈信息。

thread线程类

class Thread : noncopyable
{
 public:
  typedef std::function<void ()> ThreadFunc;
  explicit Thread(ThreadFunc, const string& name = string());
  ~Thread();
  void start();	// 创建线程
  int join();
  bool started() const { return started_; }
  pid_t tid() const { return tid_; }
  const string& name() const { return name_; }
	static int numCreated() { return numCreated_.get(); }

 private:
  void setDefaultName();

  bool       started_;
  bool       joined_;
  pthread_t  pthreadId_;
  pid_t      tid_;
  ThreadFunc func_;
  string     name_;
  CountDownLatch latch_;
  static AtomicInt32 numCreated_;
};

具体实现有些复杂,先来说说一些基本的数据成员。
started_:线程启动标记
joined_:调用了pthread_join,主线程需要等待子线程回收
pthreadId_:线程id
tid_:线程所属的进程id,muduo库采用多线程模型,不太明白保存进程id有什么用处
func_:线程入口函数
latch_:倒计时门闩,可用于线程池初始化时的同步

thread类的关键函数是start,线程启动的方式并不是直接将func_作为pthread_create的参数进行线程创建,而使用了更委婉的方法。
在Thread.cc文件,也就是thread类的实现文件里,定义了这样一个结构体:

struct ThreadData
{
  typedef muduo::Thread::ThreadFunc ThreadFunc;
  ThreadFunc func_;
  string name_;
  pid_t* tid_;
  CountDownLatch* latch_;

  ThreadData(ThreadFunc func,
             const string& name,
             pid_t* tid,
             CountDownLatch* latch)
    : func_(std::move(func)),
      name_(name),
      tid_(tid),
      latch_(latch)
  { }

  void runInThread()
  {...}
};

在start函数启动时,会先创建一个ThreadData对象,该对象拥有Thread对象的数据成员信息,并依赖于它来创建线程。

void Thread::start()
{
  assert(!started_);
  started_ = true;
  detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_);
  if (pthread_create(&pthreadId_, NULL, &detail::startThread, data))
  {
    started_ = false;
    delete data;
    LOG_SYSFATAL << "Failed in pthread_create";
  }
  else
  {
    latch_.wait();
    assert(tid_ > 0);
  }
}

这里的startThread是一个外部的函数,以ThreadData对象作为参数,该函数最终会调用ThreadData对象的runInThread成员函数,这时才会会真正地调用线程入口函数func_。
线程的信息会保存在CurrentThread命名空间里,该命名空间的变量都用__thread修饰。该关键字表示该变量是线程独享的。
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值