zoukankan      html  css  js  c++  java
  • 整理:一个简单的基于策略的多线程LogSystem(1)

        这个周面试一家公司,面谈中要求提供代码片段,但招聘启事上没有注明。自己也囧了下,发现自己工作职位,地点一直变动,最近一年转作程序员,但课余时间还没有自己写一些小程序。当即觉得是该开始这种小积累的时候了。不积跬步,无以至千里。

        自己之前在某游戏公司项目中,负责写一个服务器的网络通信代码,当时基于iocp模型下编写的,也是那时开始学习网络编程。印象深刻的是当时调试时记录一些线程内的打印消息时,因为多线程的关系比较麻烦,原来的代码中log不好用,一直是我比较纠结的地方(不是重点却让你很不爽哈)。收拾当时的抑郁心情,把自己希望这个小log能够实现以下几个小功能:

        1    支持多线程下的log记录。

        2    支持向多个console或file内写入log

        3    log可模块化。主项目中的不同模块都可以有自己的log模块。

        4    可以方面的设置log开关。可用配置文件或使用编译条件开打开。

        5    追踪函数调用。(目前版本暂不支持)

     

    因为最近一直在看模板方面的东西,特别是loki库。就把这个logsystem作为模板设计的一个尝试。该程序参考了《游戏编程精粹3》中的基于策略的logsystem(117页)。

    希望能够如下使用:

    View Code
    unsigned int WINAPI threadfunc1_in_module1(void* i)
    {
    for(int i = 0; i < 500; i++)
    logx(
    1)<< i << "\tthreadfunc1_in_module1 " << " 11\n";
    //logx(1).print("%d\tthreadfunc1_in_module1 11\n", i);

    endTime
    = GetCurrentTime();
    return 0;
    }

      logx(1)即为获得模块1的的全局logger。重载流操作符,并可级联使用。logx最终把字符输入文件或console中。设置不打开log开关时,该语句将跳过后边的<<输入语句,减少负担。基本的想法如此。logx为一个宏,而不是一个函数,防止了不必要的参数压栈。

        1  需要一个队列。工作线程中输入的log都发送到这个队列中。然后单独用一个线程读取该队列完成IO操作。这样避免了在工作线程中进行慢速的IO操作。

        2  因为需要级联输入,意味着并不是每次调用<<时,就表示使用者已经结束log输入。基于这个考虑,我们需要一个缓冲区,来储存所有级联调用输入的字符,而每次writelog前,判断缓冲区是否为空,不为空则将内容发送出去,再把缓冲区清空。

        队列中应该直接保存字符串指针的话,不容易支持2,对于每一个log字符串,我们将其保存在一个LogItem里进行处理,队列保存的是LogItem。如此看上去会更舒服和方便。

        LogItem还可以直接作为上层结构的缓冲区,这样就上层结构就不需要特设一个缓冲类了。当然上层结构也可以接受一个模板参数作为缓冲区的策略。

        LogItem因为与数据的紧密联系,由它支持对数据的输入转换是最自然的。因此LogItem要支持对字符串,整型,浮点型等的输入输出,上层构件不需要关心这些细节了。

        LogItem的功能结构:

            1    显然需要提供一个储存字符串的buffer。

            2    提供对标准输出和文件输出的支持。

            3    因为上层结构会操纵它,重载操作符=也是方便的。

            4    重载<<操作符支持泛型输入。

        LogItem作为上层结构的一个策略,可以自己定制然后作为策略传入上层结构。

        对于LogItem的字符buffer,需要考虑其内存是在运行期或编译期分配。我个人通过传入一个size_t的模板参数在编译期分配好该buffer,一般项目中每次log的字符长度基本自己都有数。若是使用运行期分配,建议使用一个好的内存池,推荐Loki中的SmallObject。

       

    View Code
    #ifndef __LogItem_H__
    #define __LogItem_H__

    #include
    "stdafx.h"

    using namespace std;//为示例方便,直接使用std名字空间


    template
    <size_t ItemSize_ = 128>
    class LogItem
    {
    public:
    typedef LogItem
    <ItemSize_> ItemType;
    static const size_t ItemSize = ItemSize_;

    private:
    char m_logStr[ItemSize_]; //不支持动态大小
    size_t m_len;

    public:
    explicit ItemType():m_len(0) { init(); }

    explicit ItemType(ItemType& item)
    {
    assert(m_logStr
    && item.m_logStr);
    assert(m_logStr
    != & item);
    memcpy(m_logStr, item.m_logStr, m_len
    + 1);
    m_len
    = item.m_len;
    }

    public:
    void init() {
    reset();
    }

    void reset() {
    m_len
    = 0;
    }

    bool empty() {
    return !m_len;
    }

    ItemType
    & operator << (const char* str)
    {
    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }


    ItemType
    & operator << (const unsigned char* str)
    {
    size_t len
    = strlen(reinterpret_cast<const char*>(str));

    //暂不支持动态大小
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }


    ItemType
    & operator << (const char& c)
    {
    assert(
    1 < ItemSize_ - m_len);

    //m_len += len;
    m_logStr[m_len] = c;
    m_len
    += 1;
    m_logStr[m_len]
    = '\0';

    return *this;
    }


    ItemType
    & operator << (const int& iValue)
    {
    char str[24];
    //_itoa(iValue, str, 10);
    sprintf_s(str, 24, "%d", iValue);

    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }

    ItemType
    & operator << (const unsigned int& iValue)
    {
    char str[24];
    //_itoa(iValue, str, 10);
    sprintf_s(str, 24, "%u", iValue);

    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }

    ItemType
    & operator << (const bool& iValue)
    {
    return (*this) << static_cast<int>(iValue);
    }

    ItemType
    & operator << (const short& iValue)
    {
    return (*this) << static_cast<int>(iValue);
    }

    ItemType
    & operator << (const unsigned short& iValue)
    {
    return (*this) << static_cast<short>(iValue);
    }

    ItemType
    & operator << (const long& lValue)
    {
    char str[24];
    sprintf_s(str,
    24, "%ld", lValue);

    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }

    ItemType
    & operator << (const unsigned long& lValue)
    {
    char str[24];
    sprintf_s(str,
    24, "%lu", lValue);

    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }

    ItemType
    & operator << (const double& dValue)
    {
    char str[32];
    sprintf_s(str,
    32, "%f", dValue);

    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }

    ItemType
    & operator << (const float& fValue)
    {
    char str[32];
    sprintf_s(str,
    32, "%f", fValue);

    size_t len
    = strlen(str);

    //暂不支持动态分配
    assert(len < ItemSize_ - m_len);

    memcpy( m_logStr
    + m_len, str, len );
    m_len
    += len;
    m_logStr[m_len]
    = '\0';

    return *this;
    }


    const ItemType& operator = (ItemType& item)
    {
    assert(
    this != &item);
    assert(m_logStr
    && item.m_logStr);

    memcpy(m_logStr, item.m_logStr, item.m_len
    + 1);
    m_len
    = item.m_len;

    return *this;
    }

    //标准输出
    friend ostream& operator << (ostream& os, ItemType& item)
    {
    os
    << item.m_logStr;
    return os;
    }

    //文件输出
    friend fstream& operator << (fstream& fs, ItemType& item)
    {
    fs
    << item.m_logStr;
    return fs;
    }
    };

    #endif

    上层结构于是可以通过模板参数定义一个大小为Size的LogItem:

        typedef LogItem<Size = 128> ItemType;

    一个Log System的基础构件如上。接下来需要实现LogQueue,作为item的集合,方便LogSystem对item的管理。

    整个LogSystem基本的结构为:

        LogManager    ->    LogQueue    ->    LogItem

  • 相关阅读:
    SSRF——和远程文件包含的区别在于远程文件包含多是包含攻击者的主机文件,SSRF是内网主机的文件
    SSRF中的绕过手段——字节总结得比较好,如何绕过SSRF的保护机制,DNS欺骗,使用IPV6地址,十六进制编码、八进制编码、双字编码、URL编码和混合编码等
    SSRF——服务端请求伪造,根因是file_get_contents,fsockopen,curl_exec函数调用,类似远程文件包含,不过是内网机器
    文件包含——本地文件包含和远程文件包含
    文件包含和目录遍历区别——目标都是信息泄露,但手段一个是利用函数来包含web目录以外的文件,另外一个是对web路径访问权限设置不严格导致
    DFS——单词分割,原来还是要使用cached dp才能避免不超时
    模块module间引用和使用本地maven库的jar包
    机器学习西瓜书白话解读笔记---0401-0404、信息和熵的度量
    机器学习实战笔记---0、读大纲
    心得体悟帖---201129(【社会规律】)
  • 原文地址:https://www.cnblogs.com/flytrace/p/2152225.html
Copyright © 2011-2022 走看看