赞
踩
stressapptest 是一个用于测试系统稳定性和可靠性的开源应用程序。它通过模拟在系统上运行的压力,并检查系统在这种严格条件下的稳定性。stressapptest 是一个非常有用的工具,可以在不同环境中对系统进行稳定性测试和故障排除。
Logger类的定义,它提供了日志记录的功能和相关操作。
#include <pthread.h> #include <stdarg.h> #include <string> #include <vector> #include "sattypes.h" static const size_t kMaxQueueSize = 250; #define LOGGER_ASSERT(x) \ {\ if (!(x)) {\ fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\ exit(1);\ }\ } class Logger { public: // Returns a pointer to the single global Logger instance. Will not return // NULL. static Logger *GlobalLogger(); // Lines with a priority numerically greater than this will not be logged. // May not be called while multiple threads are running. virtual void SetVerbosity(int verbosity) { verbosity_ = verbosity; } virtual void SetLogFd(int log_fd) { LOGGER_ASSERT(log_fd >= 0); log_fd_ = log_fd; } // Set output to be written to stdout only. This is the default mode. May // not be called while multiple threads are running. virtual void SetStdoutOnly() { log_fd_ = -1; } // Enable or disable logging of timestamps. void SetTimestampLogging(bool log_ts_enabled) { log_timestamps_ = log_ts_enabled; } void VLogF(int priority, const char *format, va_list args); void StartThread(); void StopThread(); protected: Logger(); virtual ~Logger(); private: // Args: // line: Must be non-NULL. This function takes ownership of it. void QueueLogLine(string *line); // Args: // line: Must be non-NULL. This function takes ownership of it. void WriteAndDeleteLogLine(string *line); // Callback for pthread_create(3). static void *StartRoutine(void *ptr); // Processes the log queue. void ThreadMain(); pthread_t thread_; int verbosity_; int log_fd_; bool thread_running_; bool log_timestamps_; vector<string*> queued_lines_; // This doubles as a mutex for log_fd_ when the logging thread is not running. pthread_mutex_t queued_lines_mutex_; // Lets the logging thread know that the queue is no longer empty. pthread_cond_t queued_lines_cond_; // Lets the threads blocked on the queue having reached kMaxQueueSize know // that the queue has been emptied. pthread_cond_t full_queue_cond_; DISALLOW_COPY_AND_ASSIGN(Logger); };
类的主要功能和细节:
Logger 类设计为支持多线程环境,采用了互斥锁和条件变量进行线程同步控制,确保多线程情况下的安全访问。其中,QueueLogLine方法和ThreadMain方法中对互斥锁的使用尤为重要。
在方法QueueLogLine中,对line指针进行了判空处理,确保了line指针的有效性。在WriteAndDeleteLogLine方法中对line指针进行了删除操作,释放了内存资源。
StartThread方法负责启动专用日志记录线程,StopThread方法负责终止线程。线程的启动和结束通过pthread_create和pthread_join来实现。
日志的时间戳记录和文件输出:VLogF方法负责记录日志,支持时间戳记录和分级别的日志输出。线程独立的日志记录功能由专用日志记录线程来实现,以提高效率。
WriteAndDeleteLogLine方法中实现了向文件描述符和标准输出的写入操作。
GlobalLogger方法通过静态局部变量实现了Logger类的单例模式,保证了全局只有一个Logger实例。
StartThread() 和StopThread()是Logger 类中用于启动和停止专用日志记录线程的函数实现。
void Logger::StartThread() { LOGGER_ASSERT(!thread_running_); thread_running_ = true; LOGGER_ASSERT(0 == pthread_create(&thread_, NULL, &StartRoutine, this)); } void Logger::StopThread() { // Allow this to be called before the thread has started. if (!thread_running_) { return; } thread_running_ = false; int retval = pthread_mutex_lock(&queued_lines_mutex_); LOGGER_ASSERT(0 == retval); bool need_cond_signal = queued_lines_.empty(); queued_lines_.push_back(NULL); retval = pthread_mutex_unlock(&queued_lines_mutex_); LOGGER_ASSERT(0 == retval); if (need_cond_signal) { retval = pthread_cond_signal(&queued_lines_cond_); LOGGER_ASSERT(0 == retval); } retval = pthread_join(thread_, NULL); LOGGER_ASSERT(0 == retval); } void *Logger::StartRoutine(void *ptr) { Logger *self = static_cast<Logger*>(ptr); self->ThreadMain(); return NULL; }
在 StartThread 方法中:
在 StopThread 方法中:
在这段代码中,使用了条件变量和互斥锁来实现线程的同步控制与通信。值得注意的是:
主要是 Logger 类中用于处理队列日志行和写入日志的函数实现。使用了互斥锁和条件变量来实现线程同步控制与通信,保证了对队列的安全操作和日志写入的正确性。同时,在对指针进行相关操作时,使用断言进行合法性检查,确保了代码的稳定性和正确性。
void Logger::QueueLogLine(string *line) { LOGGER_ASSERT(line != NULL); LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_)); if (thread_running_) { if (queued_lines_.size() >= kMaxQueueSize) { LOGGER_ASSERT(0 == pthread_cond_wait(&full_queue_cond_, &queued_lines_mutex_)); } if (queued_lines_.empty()) { LOGGER_ASSERT(0 == pthread_cond_signal(&queued_lines_cond_)); } queued_lines_.push_back(line); } else { WriteAndDeleteLogLine(line); } LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_)); } void Logger::WriteAndDeleteLogLine(string *line) { LOGGER_ASSERT(line != NULL); ssize_t bytes_written; if (log_fd_ >= 0) { bytes_written = write(log_fd_, line->data(), line->size()); LOGGER_ASSERT(bytes_written == static_cast<ssize_t>(line->size())); } bytes_written = write(STDOUT_FILENO, line->data(), line->size()); LOGGER_ASSERT(bytes_written == static_cast<ssize_t>(line->size())); delete line; }
在 QueueLogLine 方法中:
在 WriteAndDeleteLogLine 方法中:
void Logger::VLogF(int priority, const char *format, va_list args) { if (priority > verbosity_) { return; } char buffer[4096]; size_t length = 0; if (log_timestamps_) { time_t raw_time; time(&raw_time); struct tm time_struct; localtime_r(&raw_time, &time_struct); length = strftime(buffer, sizeof(buffer), "%Y/%m/%d-%H:%M:%S(%Z) ", &time_struct); LOGGER_ASSERT(length); // Catch if the buffer is set too small. } length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args); if (length >= sizeof(buffer)) { length = sizeof(buffer); buffer[sizeof(buffer) - 1] = '\n'; } QueueLogLine(new string(buffer, length)); }
根据传入的日志优先级(priority)和日志输出级别(verbosity_)进行判断,如果priority大于verbosity_,则说明该日志信息不需要记录,直接返回。如果需要记录日志,则按照日志格式进行处理,并调用QueueLogLine方法将日志加入到日志队列中。
在方法实现中,具体的流程包括:
流程图:
此实现使用了字符串格式化函数vsnprintf和时间格式化函数strftime,辅以合理的长度检查和条件判断,保证了日志信息处理的完整性和正确性。同时,使用QueueLogLine方法将日志加入队列,确保了多线程环境下的日志记录安全。
该方法用于专门的日志记录线程的主要逻辑。
void Logger::ThreadMain() { vector<string*> local_queue; LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_)); for (;;) { if (queued_lines_.empty()) { LOGGER_ASSERT(0 == pthread_cond_wait(&queued_lines_cond_, &queued_lines_mutex_)); continue; } // We move the log lines into a local queue so we can release the lock // while writing them to disk, preventing other threads from blocking on // our writes. local_queue.swap(queued_lines_); if (local_queue.size() >= kMaxQueueSize) { LOGGER_ASSERT(0 == pthread_cond_broadcast(&full_queue_cond_)); } // Unlock while we process our local queue. LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_)); for (vector<string*>::const_iterator it = local_queue.begin(); it != local_queue.end(); ++it) { if (*it == NULL) { // NULL is guaranteed to be at the end. return; } WriteAndDeleteLogLine(*it); } local_queue.clear(); // We must hold the lock at the start of each iteration of this for loop. LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_)); } }
主要包括以下流程:
流程图:
在流程图中,首先会判断queued_lines是否为空,如果队列不为空,则将日志行从全局队列中移动到本地队列。然后判断本地队列是否已满,如果已满则发送队列满信号,否则释放全局锁,然后对每行进行写入操作。最后清空本地队列并进行下一轮的循环。
该方法主要负责专门的日志记录线程的日志写入操作,并通过使用本地队列进行写入,从而避免了在写入过程中阻塞其他线程。同时,使用互斥锁和条件变量对线程进行了同步控制,确保了在多线程环境下的安全写入。
分析了Logger类的一些关键方法和功能,包括启动和停止日志记录线程、日志队列操作、时间戳记录、日志行格式化、以及专门的日志记录线程逻辑。
Logger类提供了多线程环境下的高效日志记录功能,并且在设计上考虑了线程同步、异常处理以及内存管理等方面。它实现了多线程环境下的安全日志记录。
通过对每个方法的详细分析更好地理解这些方法的执行逻辑和线程之间的交互关系。这有助于我们深入理解和掌握Logger类的工作原理和功能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。