用pthread_create接管静态成员方法__part1

preface

#ifndef __MANAGE_HPP__
#define __MANAGE_HPP__
#include "log.hpp"
#include "commonlib.hpp"

class Empty {
};
template<class thd, class DATA = Empty>
class Manage {
public:
  //virtual int crea(thd *&t, DATA *para = NULL, string str = "");
  //run thread
  static int attachthread(thd &t);
  //stop thread
  static int stop(thd &t);
  //del thread object
  static int del(thd *t);
};
#include "manage.inl"
#endif
	//log类静态成员对象完成日志级别、文件等设置,
	//log是类名, logt指向单例log类静态成员,代表一个指针
	if(0 != Manage<log>::attachthread(*logt())) 
	{
		//运行日志thread失败
		record(__FILE__, __LINE__, errlevel, "failed."); 
		return -1;
	}
	//现在可以使用log2file把日志写入日志文件了
	log2file(__FILE__, __LINE__, level, "log ok.");

一、

二、

三、

从两个角度来表述


1、为什么要创建新线程?

日志系统需要单独一个线程,核心原因是异步写日志

如果没有独立线程(同步写日志)

业务线程
   ↓
调用 log2file()
   ↓
直接写磁盘  ← 磁盘 I/O 很慢,可能几毫秒到几十毫秒
   ↓
写完才能继续业务逻辑   ← 业务被阻塞了!

有了独立日志线程(异步写日志)

业务线程                        日志线程(独立运行)
   ↓                                  ↓
调用 log2file()                    不断从队列取日志
   ↓                                  ↓
把日志消息塞进队列            写入磁盘文件
   ↓(立刻返回,不等待)
继续执行业务逻辑

好处很明显:

  • 业务线程不被 I/O 阻塞,性能更好
  • 日志线程专职写盘,有序、不竞争
  • 多个业务线程都可以同时往队列里丢日志,日志线程统一消费

2、*logt() 传进 attachthread() 有什么用?

先看调用:

Manage<log>::attachthread(*logt());
//                               ↑
//                        解引用,得到 log类的 对象的引用

attachthread() 的签名是:

static int attachthread(thd &t);  // 接收的是引用

所以 *logt() 传进去之后,在 attachthread() 内部就是 t,它的作用贯穿整个函数:

// 1. 用它来同步(父子线程握手)
t.lock();
t.wait_cond();
t.sig_cond();
t.unlock();

// 2. 把它的指针传给新线程作为参数
thd *pt = dynamic_cast<thd*>(&t);
pthread_create(&tid, &a, start_routine, (void *)pt);
//                                          ↑
//                               新线程拿到这个指针后
//                               就能操作 log类的 对象本身

关键点:新线程拿到的是同一个对象

logt()          返回 log类 的单例指针
*logt()         解引用为对象引用,传入 attachthread()
&t → pt       在 attachthread() 内部取回指针
pthread_create    把 pt 传给新线程的入口函数 newthreadname

所以新线程启动后,拿到的 ptlogt() 指向的是同一个 log类的 对象,可以直接调用它的方法(读队列、写日志、更新状态等)。

整体关系图

主线程
  logt() ──────────────────────────┐
      ↓                                          │ 同一个对象
  *logt() 传入 attachthread()               │
      ↓                                                  │
  pthread_create(pt) ─────→ 日志线程
                                                │
                                        start_routine(pt)
                                                ↓
                                      pt->attachthread()  // log类 的业务循环
                                     从队列取日志,写文件...

简单说:*logt() 传进去,就是告诉 Manage——“帮我把这个日志对象跑在一个新线程里”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值