Web服务器---TinyWebServer代码详细讲解(log模块)

log是日志模块,一个合格的服务器当然少不了日志来记录错误异常等等信息。我们想设计一个日志模块,他能顺利写日志但是又不要占用主线程时间去写,所以我们设计异步写日志的模块。

基础知识

日志,由服务器自动创建,并记录运行状态,错误信息,访问数据的文件。
同步日志,日志写入函数与工作线程串行执行,由于涉及到I/O操作,当单条日志比较大的时候,同步模式会阻塞整个处理流程,服务器所能处理的并发能力将有所下降,尤其是在峰值的时候,写日志可能成为系统的瓶颈。

生产者-消费者模型,并发编程中的经典模型。以多线程为例,为了实现线程间数据同步,生产者线程与消费者线程共享一个缓冲区,其中生产者线程往缓冲区中push消息,消费者线程从缓冲区中pop消息。

阻塞队列,将生产者-消费者模型进行封装,使用循环数组实现队列,作为两者共享的缓冲区。

异步日志,将所写的日志内容先存入阻塞队列,写线程从阻塞队列中取出内容,写入日志。

单例模式,最简单也是被问到最多的设计模式之一,保证一个类只创建一个实例,同时提供全局访问的方法。

单例模式

单例模式作为最常用的设计模式之一,保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

实现思路:私有化它的构造函数,以防止外界创建单例类的对象;使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。

单例模式有两种实现方法,分别是懒汉和饿汉模式。顾名思义,懒汉模式,即非常懒,不用的时候不去初始化,所以在第一次被使用时才进行初始化;饿汉模式,即迫不及待,在程序运行时立即初始化。

经典的线程安全懒汉模式

 1class single{
   
 2private:
 3    //私有静态指针变量指向唯一实例
 4    static single *p;
 5
 6    //静态锁,是由于静态函数只能访问静态成员
 7    static pthread_mutex_t lock;
 8
 9    //私有化构造函数
10    single(){
   
11        pthread_mutex_init(&lock, NULL);
12    }
13    ~single(){
   }
14
15public:
16    //公有静态方法获取实例
17    static single* getinstance();
18
19};
20
21pthread_mutex_t single::lock;
22
23single* single::p = NULL;
24single* single::getinstance(){
   
25    if (NULL == p){
   
26        pthread_mutex_lock(&lock);
27        if (NULL == p){
   
28            p = new single;
29        }
30        pthread_mutex_unlock(&lock);
31    }
32    return p;
33}

为什么要用双检测,只检测一次不行吗?
如果只检测一次,在每次调用获取实例的方法时,都需要加锁,这将严重影响程序性能。双层检测可以有效避免这种情况,仅在第一次创建单例的时候加锁,其他时候都不再符合NULL == p的情况,直接返回已创建好的实例。

局部静态变量之线程安全懒汉模式

前面的双检测锁模式,写起来不太优雅,《Effective C++》(Item 04)中的提出另一种更优雅的单例模式实现,使用函数内的局部静态对象,这种方法不用加锁和解锁操作。

 1class single{
   
 2private:
 3    single(){
   }
 4    ~single(){
   }
 5
 6public:
 7    static single* getinstance();
 8
 9};
10
11single* single::getinstance(){
   
12    static single obj;
13    return &obj;
14}

如果使用C++11之前的标准,还是需要加锁,这里同样给出加锁的版本

 1class single{
   
 2private:
 3    static pthread_mutex_t lock;
 4    single(){
   
 5        pthread_mutex_init(&lock, NULL);
 6    }
 7    ~single(){
   }
 8
 9public:
10    static single* getinstance();
11
12};
13pthread_mutex_t single::lock;
14single* single::getinstance(){
   
15    pthread_mutex_lock(&lock);
16    static single obj;
17    pthread_mutex_unlock(&lock);
18    return &obj;
19}

饿汉模式

饿汉模式不需要用锁,就可以实现线程安全。原因在于,在程序运行时就定义了对象,并对其初始化。之后,不管哪个线程调用成员函数getinstance(),都只不过是返回一个对象的指针而已。所以是线程安全的,不需要在获取实例的成员函数中加锁。

 1class single{
   
 2private:
 3    static single* p;
 4    single(){
   }
 5    ~single(){
   }
 6
 7public:
 8    static single* getinstance();
 9
10};
11single* single::p = new single(
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值