Lazy loaded image
考研
tinyWebServer 学习笔记——四、日志系统
字数 3605阅读时长≈ 10 分钟
2026-10-16
2026-10-16

一、基础知识

1. 概念

1
流程图[2]
  • 日志:由服务器自动创建,用于记录运行状态和错误信息;
  • 同步日志:日志写入函数与工作线程串行执行,由于涉及到 I/O 操作,当单条日志较大时,同步模式会阻塞整个处理流程,服务器所能处理的并发能力将有所下降,易称为性能的瓶颈;
  • 异步日志:将所写的日志内容先存入缓存队列,写线程从阻塞队列中去除内容,写入日志;
  • 生产者/消费者模型:生产者与消费者共享一个缓冲区,生产者往缓冲区添加消息,消费者从缓冲区中处理消息;
  • 阻塞队列:将生产者/消费者模型进行封装,使用循环数组实现队列,作为两者共享的缓存区;
  • 单例模式:保证一个类只创建一个实例,同时提供全局访问的方法,单例模式有懒汉模式与饿汉模式,前者在第一次使用时进行初始化,后者在程序运行时初始化;
  • 日志分级:一般提供五种级别:
  • Debug :调试代码时的输出,在系统实际运行时,一般不使用;
  • Warn :调试代码时使用的终端警告;
  • Info :报告系统当前的状态,当前执行的流程或接收的信息等;
  • Error 和 Fatal :输出系统的错误信息;
  • 日志分文件:根据日期、行数判断是否需要份文件;

2. API

  • pthread_cond_init 函数:用于初始化条件变量;
  • pthread_cond_destory 函数:销毁条件变量;
  • pthread_cond_broadcast 函数:以广播的方式唤醒所有等待目标条件变量的线程;
  • pthread_cond_wait 函数:用于等待目标条件变量,调用时传入 mutex 参数(加锁的互斥锁),执行时先把调用线程放入条件变量的请求队列,然后将互斥锁解锁,成功时返回 0 ,表示重新抢到了互斥锁,将其再次锁上,因此函数内部会有一次解锁和加锁操作,使用方法如下:
    • 由 API 介绍可知,在使用 pthread_cond_wait 函数前需要加锁,这是为了避免资源竞争,使得每个线程互斥访问公有资源。
    • 在函数内部将互斥锁解锁,是因为函数会阻塞自己,此时它仍持有互斥锁,若不解锁则其他线程无法访问公有资源。
    • 在对互斥锁解锁前需要将调用线程放入请求队列,这是因为如果在把调用线程放入等待队列之前就释放互斥锁,会导致其他线程获得互斥锁从而访问公有资源,此时调用线程锁等待的条件改变了,但是它没有被放在等待队列上,导致调用线程忽略了等待条件被满足的信号,发生错误。
    • 当调用线程放在条件变量之后,将互斥锁解锁,此时等待被唤醒,若成功竞争到互斥锁,再次加锁来访问公共资源。
    • int fputs(const char *str, FILE *stream); :
    • str :一个包含了要写入的以空字符终止的字符序列;
    • stream :指向 FILE 对象的指针,标识了被写入字符串的流;
    • __VA_ARGS__ :可变参数的宏,可以在宏定义中使用省略号,若加 ## 则更健壮,可以在可变参数为 0 时将逗号去掉:
      • int fflush(FILE *stream); :强迫缓存区内的数据协会参数 stream 指定的文件中,如果参数为 NULL ,则会将所有打开的文件数据更新。该函数主要用于防止新到的数据冲掉未输出完数据的缓冲区(即覆盖了原有数据),通常将其放在 printf 函数之后。

      二、代码解析

      1. 单例模式

      经典的懒汉模式:
      优雅的懒汉模式:
      饿汉模式:

      2. 阻塞队列

      3. 日志类定义

      4. 生成日志文件并判断写入方式

      5. 日志分级与分文件

      参考文献

      原创存证 · 本地哈希 · 3fbaa1812b4d...
      算法:SHA-256
      时间:2026-10-16
      哈希:3fbaa1812b4d35317803f6ab7d009335287cf2f6bf5885f36938443faf8d054b

      该信息用于辅助证明当前内容版本,不等同于法律公证或版权登记。


      评论
      Loading...