Sylar_网络框架学习——线程模块(三)

16-25课

日志模块+配置模块整合

/*
0.创建log文件对应的配置指针	log.cpp:590
sylar::ConfigVar<std::set<LogDefine> >::ptr g_log_define = 
    sylar::Config::Lookup("logs", std::set<LogDefine>(), "logs config");

在构造函数中,加入该配置对应的回调函数,并将其声明为静态变量,使其在main之前初始化
struct LogIniter{
	LogIniter() {
		g_log_define->addListener(匿名函数)
	}
}
static LogIniter __log_init;

1.加载yaml文件	sylar::Config::LoadFromYaml(root);
2.LoadFromYaml中解析yaml,将yaml格式化为string:yaml;依次取出,判断key是否存在于std::map<std::string, ConfigVarBase::ptr>中
3.通过ConfigVarBase基类指针调用ConfigVar::fromString()方法,执行setValue()方法
4.setValue中若旧值和新值不同,触发回调函数
*/

1) LogDefine

log的基本配置信息

struct LogDefine {
    std::string name;
    LogLevel::Level level = LogLevel::UNKNOW;
    std::string formatter;
    std::vector<LogAppenderDefine> appenders;

    bool operator==(const LogDefine& oth) const {
        return name == oth.name
            && level == oth.level
            && formatter == oth.formatter
            && appenders ==oth.appenders;
    }

    bool operator<(const LogDefine& oth) const {
        return name < oth.name;
    }
};

2) LogAppenderDefine

logappender的基本配置信息

struct LogAppenderDefine {
    int type = 0;       //1 File  2 Stdout
    LogLevel::Level level = LogLevel::UNKNOW;
    std::string formatter;
    std::string file;

    bool operator==(const LogAppenderDefine& oth) const {
        return type == oth.type
            && level == oth.level
            && formatter == oth.formatter
            && file == oth.file;
    }
};

3) LogDefine和set之间的偏特化

template<>
class LexicalCast<std::string, std::set<LogDefine> > {
public:
    std::set<LogDefine> operator() (const std::string& v) {
        YAML::Node node = YAML::Load(v);
        std::set<LogDefine> vec;
        for(size_t i = 0; i < node.size(); ++i){
            auto n=node[i];
            if(!n["name"].IsDefined()) {
                std::cout<<"log config error: name is null, " << n
                         << std::endl;
                continue;
            }
            LogDefine ld;
            ld.name = n["name"].as<std::string>();
            ld.level = LogLevel::FromString(n["level"].IsDefined() ? n["level"].as<std::string>() : "");
            if(n["formatter"].IsDefined()) {
                ld.formatter = n["formatter"].as<std::string>();
            }
            if(n["appenders"].IsDefined()){
                for(size_t x = 0; x < n["appenders"].size(); ++x) {
                    auto a = n["appenders"][x];
                    if(!a["type"].IsDefined()) {
                        std::cout << "log config error: appenders.type is null, " << a << std::endl;
                        continue;
                    }
                    std::string type = a["type"].as<std::string>();
                    LogAppenderDefine lad;

                    if(type == "FileLogAppender"){
                        lad.type = 1;
                        if(!a["file"].IsDefined()){
                            std::cout << "log config error: fileappenders.file is null, " << a << std::endl;
                            continue;
                        }
                        lad.file = a["file"].as<std::string>();
                    }
                    else if(type == "StdoutLogAppender"){
                        lad.type = 2;
                    }
                    else{
                        std::cout << "log config error: appenders.type is invaild, " << a << std::endl;
                        continue;
                    }
                    ld.appenders.push_back(lad);
                }
            }
            vec.insert(ld);
        }
        return vec;
    }
};

template<>
class LexicalCast<std::set<LogDefine>, std::string> {
public:
    std::string operator() (const std::set<LogDefine>& v) {
        YAML::Node node;
        for(auto& i : v){
            YAML::Node n;
            n["name"] = i.name;
            if(i.level != LogLevel::UNKNOW) {
                n["level"] = LogLevel::ToString(i.level);
            }
            
            if(i.formatter.empty()){
                n["formatter"] = i.formatter;
            }
            for(auto& a:i.appenders){
                YAML::Node na;
                if(a.type==1){
                    na["type"] = "FileLogAppender";
                    na["file"] = a.file;
                }
                else if(a.type==2){
                    na["type"] = "StdoutLogAppender";
                }
                if(a.level != LogLevel::UNKNOW) {
                    na["level"] = LogLevel::ToString(a.level);
                }
                if(!a.formatter.empty()){
                    na["formatter"] = a.formatter;
                }
                n["appenders"].push_back(na);
            }
            node.push_back(n);
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }
};

4) toYamlString()

实现将当前配置输出为string

LoggerManger::toYamlString() —》 Logger::toYamlString() —》 LogAppender::toYamlString() 虚函数 --> StdoutLogAppender::toYamlString()

​ |

​ V

​ FileLogAppender::toYamlString()

线程模块

通过封装semaphore和pthread实现

1) 信号量

class Semaphore {
public:
    Semaphore(uint32_t count = 0);
    ~Semaphore();

    void wait();
    void notify();
private:
    Semaphore(const Semaphore&) = delete;
    Semaphore(const Semaphore&&) = delete;
    Semaphore& operator=(const Semaphore&) = delete;

private:
    sem_t m_semaphore;
}; 

2) 锁模板

通过模板的方式实现,离开锁的作用域后先解锁,再析构锁

template<class T>
struct ScopedLockImpl {
public:
    ScopedLockImpl(T& mutex)
        :m_mutex(mutex) {
            m_mutex.lock();
            m_locked = true;
    }
    ~ScopedLockImpl() {
        unlock();
    }
    void lock() {
        if(!m_locked) {
            m_mutex.lock();
            m_locked = true;
        }
    }
    void unlock() {
        if(m_locked) {
            m_mutex.unlock();
            m_locked = false;
        }
    }
private:
    T& m_mutex;
    bool m_locked;
};

3) 互斥锁

同一时间只允许一个线程使用共享资源,读写速度较慢

包含ScopedLockImpl< Mutex >,当锁离开了作用域后先调用ScopedLockImpl::~ScopedLockImpl()析构函数实现解锁操作,再进行析构锁

class Mutex{
public:
    typedef ScopedLockImpl<Mutex> Lock;
    Mutex() {
        pthread_mutex_init(&m_mutex, nullptr);
    }
    ~Mutex() {
        pthread_mutex_destroy(&m_mutex);
    }
    void lock() {
        pthread_mutex_lock(&m_mutex);
    }
    void unlock() {
        pthread_mutex_unlock(&m_mutex);
    }
private:
    pthread_mutex_t m_mutex;
};

4) 读写锁

读写分离,封装pthread_rwlock

速度较快,适合读多写少的情况

//读写模板
template<class T>
struct ReadScopedLockImpl {
public:
    ReadScopedLockImpl(T& mutex)
        :m_mutex(mutex) {
            m_mutex.rdlock();
            m_locked = true;
    }
    ~ReadScopedLockImpl() {
        unlock();
    }

    void lock() {
        if(!m_locked) {
            m_mutex.rdlock();
            m_locked = true;
        }
    }

    void unlock() {
        if(m_locked) {
            m_mutex.unlock();
            m_locked = false;
        }
    }
private:
    T& m_mutex;
    bool m_locked;
};
template<class T>
struct WriteScopedLockImpl {
public:
    WriteScopedLockImpl(T& mutex)
        :m_mutex(mutex) {
            m_mutex.wrlock();
            m_locked = true;
    }
    ~WriteScopedLockImpl() {
        unlock();
    }

    void lock() {
        if(!m_locked) {
            m_mutex.wrlock();
            m_locked = true;
        }
    }

    void unlock() {
        if(m_locked) {
            m_mutex.unlock();
            m_locked = false;
        }
    }
private:
    T& m_mutex;
    bool m_locked;
};
//读写锁
class RWMutex {
public:
    typedef ReadScopedLockImpl<RWMutex> ReadLock;
    typedef WriteScopedLockImpl<RWMutex> WriteLock;
    RWMutex() {
        pthread_rwlock_init(&m_lock, nullptr);
    }
    ~RWMutex() {
        pthread_rwlock_destroy(&m_lock);
    }
    void rdlock() {
        pthread_rwlock_rdlock(&m_lock);
    }
    void wrlock() {
        pthread_rwlock_wrlock(&m_lock);
    }
    void unlock() {
        pthread_rwlock_unlock(&m_lock);
    }
private:
    pthread_rwlock_t m_lock;
};

5) 自旋锁

适用于快任务,每次线程操作时间较短

若无法抢占任务时,锁进行自旋操作,不会立即挂起,而是一直等待上一个线程,可以设置等待时间

会发生死锁,如果等待的线程一直阻塞,自旋锁会一直自旋等待;在自旋锁还未释放时再次申请了一个自旋锁

class Spinlock {
public:
    typedef ScopedLockImpl<Spinlock> Lock;
    Spinlock() {
        pthread_spin_init(&m_mutex, 0);
    }
    ~Spinlock() {
        pthread_spin_destroy(&m_mutex);
    }
    void lock() {
        pthread_spin_lock(&m_mutex);
    }
    void unlock() {
        pthread_spin_unlock(&m_mutex);
    }
private:
    pthread_spinlock_t m_mutex;
};

6) CAS乐观锁

无锁编程,容易引发临界资源的问题

封装原子操作,核心是比较并交换,如果想要插入的位置不是最后则一直向后移动,直至末尾开始插入

/*
A:当前值
V:内存值
B:新值
CAS(A, V, B){
	if(A == V){
		V = B;
	}
	else {
		重试或放弃
	}
}
ABA问题:A从5改为10 成功,B从5改为10 阻塞,C从10改为5 成功;这时候B采用CAS(5,5,10)判断成功,将5又改为了10,出现问题
解决:CAS判断时加入版本号,进行版本比较
*/
class CASLock {
public:
    typedef ScopedLockImpl<CASLock> Lock;
    CASLock() {
        m_mutex.clear();
    }
    ~CASLock() {
    }
    void lock() {
        while(std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
    }
    void unlock() {
        std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
    }
private:
    volatile std::atomic_flag m_mutex;
};

7) 线程

class Thread{
public:
    typedef std::shared_ptr<Thread> ptr;
    Thread(std::function<void()> cb, const std::string& name);
    ~Thread();
    pid_t getId() const {return m_id;}
    const std::string& getName() const {return m_name;}
    void join();
    static Thread* GetThis();
    static const std::string& GetName();
    static void SetName(const std::string& name);
private:
    Thread(const Thread&) = delete;
    Thread(const Thread&&) = delete;
    Thread& operator=(const Thread&) = delete;
    static void* run(void* arg);
private:
    pid_t m_id = -1;
    pthread_t m_thread = 0;
    std::function<void()> m_cb;
    std::string m_name;
    Semaphore m_semaphore;
};

日志+配置+线程整合

1) 日志

使用自旋锁,在LogAppender、Logger、LoggerManger类中加入

多线程情况时,访问资源的函数都需要考虑加锁

std::string Logger::toYamlString();
void Logger::clearAppenders();
void Logger::setFormatter(LogFormatter::ptr val);
LogFormatter::ptr Logger::getFormatter();
void LogAppender::setFormatter(LogFormatter::ptr val);
LogFormatter::ptr LogAppender::getFormatter();
void Logger::log(LogLevel::Level level, LogEvent::ptr event);
void Logger::addAppender(LogAppender::ptr appender);
void Logger::delAppender(LogAppender::ptr appender);
void StdoutLogAppender::log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event);
std::string StdoutLogAppender::toYamlString();
void FileLogAppender::log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event);
std::string FileLogAppender::toYamlString();
bool FileLogAppender::reopen();
Logger::ptr LoggerManger::getLogger(const std::string& name);
std::string LoggerManger::toYamlString();

2) 配置

使用读写锁,读多写少的情况

//ConfigVar类:
std::string toString();
const T getValue();
void setValue(const T& v);
uint64_t addListener(on_change_cb cb);
void delListtener(uint64_t key);
on_change_cb getListener(uint64_t key);
void clearListener();
//Config类
void Config::Visit(std::function<void(ConfigVarBase::ptr)> cb)
template<class T>
static typename ConfigVar<T>::ptr Lookup(const std::string& name,
            const T& default_value, const std::string& description = "");
template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name);
//ConfigVarBase类
ConfigVarBase::ptr Config::LookupBase(const std::string& name);

全部实现可见仓库,欢迎点赞。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiaoooooo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值