C++多线程日志记录器Logger简单实现

最基本的简单实现,没有实际意义,仅为博主的学习记录 《C++高级编程 第三版》 [美] Marc Gregoire 著
IDE : Code::Blocks
Compiler : GNU GCC Compiler have g++ follow the C++14 ISO C++ language standard [-std=c++14]
Console application ProjectName : LoggerMultiThread

Logger.h

#ifndef LOGGER_MULTI_THREAD_H
#define LOGGER_MULTI_THREAD_H

#include <fstream>
#include <string>
#include <queue>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <thread>

class Logger {
public:
    // 构造函数创建后台线程
    Logger() : isExited(false) {
        mThread = std::thread{&Logger::process, this};
    }

    // 显示删除复制构造函数和赋值运算符
    Logger(const Logger& src) = delete;
    Logger& operator=(const Logger& rhs) = delete;

    // 析构函数唤醒后台线程,将消息列队的信息全部写出到文件后,销毁对象
    ~Logger() {
        {
            // 上锁 (锁在此花括号代码块中有效,避免出现死锁)
            std::unique_lock<std::mutex> lock(mut);
            isExited = true;
            // 唤醒后台线程
            condVar.notify_all();
        }
        // 此时锁已释放,后台线程可获得锁
        mThread.join();
    }

    // 客户调用借口,向消息列队写入一条消息,并唤醒后台线程
    void log(const std::string& entry) {
        std::unique_lock<std::mutex> lock(mut);
        messagesQueue.push(entry);
        condVar.notify_all();
    }

private:
    // 后台线程,将消息列队中的信息写入文件
    void process() {
        std::ofstream ofs("log.txt", std::ios::out /*| std::ios::app*/);
        if (ofs.fail()) {
            std::cerr << "Failed to open logFile." << std::endl;
        }
        // 上锁
        std::unique_lock<std::mutex> lock(mut);
        while (true) {
            // 判断是否退出,若退出为假,等待唤醒
            if (!isExited) {
                condVar.wait(lock);
            }
            // 释放锁
            lock.unlock();
            while (true) {
                // 上锁,每次处理一条信息,每次处理时上锁和释放锁,防止线程阻塞时间过长
                lock.lock();
                if (messagesQueue.empty()) { break; }
                else {
                    ofs << messagesQueue.front() << std::endl;
                    messagesQueue.pop();
                }
                lock.unlock();
            }
            if (isExited) break;
        }
    }

    std::queue<std::string> messagesQueue; //! 消息列队
    std::atomic<bool> isExited; //! 退出状态 原子bool类型
    std::mutex mut; //! 非定时互斥体
    std::condition_variable condVar; //! 条件变量
    std::thread mThread; //! 线程
};

#endif // LOGGER_MULTI_THREAD_H

main.cpp

#include <iostream>
#include <sstream>
#include <functional>
#include <vector>
#include "Logger.h"

using namespace std;

void func(int id, Logger& logger) {
    // do something else.
    for (size_t i = 0; i < 74; ++i) {
        stringstream ss;
        ss << "The No." << id << " thread's test for the " << i << " times to call Logger's log.";
        logger.log(ss.str());
    }
}

void Test() {
    Logger logger;
    vector<thread> myThreads;
    for (size_t i = 0; i < 10; ++i) {
        myThreads.emplace_back(func, i, ref(logger));
    }
    for (auto& aThread : myThreads) {
        aThread.join();
    }
}

int main() {
    Test();
    return 0;
}

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

血梦墨雪

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值