1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | //Logger.h namespace netlib { class Logger { public: //ctors Logger(); //dtors //graceful quit. virtual ~Logger(); //make new log. void log(const std::string &entry); protected: void processEntries(); bool exit = false; bool threadStarted = false; bool running = false; std::mutex mutex_lock; std::condition_variable conditionVariable; std::queue<std::string> stringQueue; std::thread backgroundThread; std::mutex mutexStarted; std::condition_variable conditioVariableStarted; private: //대입연산자 생성을 방지하기 위한 함수들 //실제로 사용될 일이 없다. Logger(const Logger& src); Logger& operator=(const Logger& rhs); }; } //Logger.cpp #include "Logger.h" static const std::string dir = std::string("log/"); namespace netlib { Logger::Logger() { //make&start background thread if (!running) { backgroundThread = std::thread{ &Logger::processEntries,this }; //스레드가 처리 루프를 시작할 때까지 기다리자. std::unique_lock<std::mutex> lock(mutexStarted); conditioVariableStarted.wait(lock, [&]() {return threadStarted == true; } ); } running = true; } Logger::~Logger() { //종료 전에 강제로 백그라운드 스레드를 깨우고, //그 스레드의 종료를 기다린다. //프로그램 종료시 log가 다 기록되지 않고 프로그램이 종료되는 것을 //방지. exit = true; conditionVariable.notify_all(); backgroundThread.join(); } void Logger::log(const std::string &entry) { //락을 걸고 큐에 항목 삽입. std::unique_lock<std::mutex> lock(mutex_lock); stringQueue.push(entry); conditionVariable.notify_all(); } void Logger::processEntries() { std::ofstream outFileStream(std::string(dir + "log.txt")); auto &ofs = outFileStream; if (ofs.fail()) { std::cout << "Failed to open file" << std::endl; return; } printf("here\n"); std::unique_lock<std::mutex> lock(mutex_lock); //스레드가 처리 루프를 시작했다고 알린다 threadStarted = true; conditioVariableStarted.notify_all(); //write logs while (true) { conditionVariable.wait(lock); lock.unlock(); while (true) //<-여기 //여기서 stringqueue를 건드리면 안되는게 //stringQueue가 점유되지 않았으므로.. { lock.lock(); if (stringQueue.empty()) break; else if( stringQueue.size()>=5) { for (int i = 0; i < 5;++i) { ofs << stringQueue.front() << std::endl; std::cout << stringQueue.front() << std::endl; stringQueue.pop(); } } else { for (int i = 0; i < stringQueue.size(); ++i) { ofs << stringQueue.front() << std::endl; std::cout << stringQueue.front() << std::endl; stringQueue.pop(); } } lock.unlock(); } if (exit) break; //종료. } } } //main(unittest.cpp) #include "Logger.h" #include <iostream> #include <memory> #include <string> #include <sstream> using netlib::Logger; using namespace std; void logSomeMEssages(int id, Logger& logger) { for (int i = 0; i < 10; ++i) { stringstream ss; ss << "log entry " << i << "from thread" << id; logger.log(ss.str()); } } int main() { Logger log; vector<thread> threads; for (int i = 0; i < 10; ++i) threads.push_back(thread{ logSomeMEssages,i,ref(log) }); //여기 ref는 log를 참조로 던진다는 얘기. //중요하다. //로그는 복사되면 안된다. for (auto &t : threads) t.join(); return 0; } | cs |
dd
프로그램이 뻗었을 때 처리하는 기능도 추가해야 하는데..어렵다
n초당 로그쓰기를 한번 실행하도록 갈아치워야겠따
boost log 써