C/C++中的并发日志文件访问
Concurrent log file access in C/C++
我正在创建一个多线程程序,几个线程可能需要调用全局函数
writeLog(const char* pMsg);
writeLog将实现类似tihs:的功能
void writeLog(const char* pMsg)
{
CRITICAL_SECTION cs;
// initialize critical section
...
EnterCriticalSection(&cs);
// g_pLogFilePath is a global variable.
FILE *file;
if (0!=fopen_s(&file, g_pLogFilePath, "r+"))
return;
fprintf(file, pMsg);
fclose(file):
LeaveCriticalSection(&cs);
}
我的问题是:
1) is it the best way to do concurrent logging? i.e., using critical section.
2) since I will write log in many places in the threads,
and since each log writing will involve open/close file,
does the io will impact the performance significantly?
谢谢!
执行并发日志记录的最佳方法是使用C++的现有日志库之一。它们有许多您可能想要使用的功能(不同的附加器、格式化、并发等)。
如果你仍然想有自己的解决方案,你可能会有这样的解决方案:初始化一次并保持状态(文件处理程序和互斥对象)的简单单例
class Log
{
public:
// Singleton
static Log & getLog()
{
static Log theLog;
return theLog;
}
void log(const std::string & message)
{
// synchronous writing here
}
private:
// Hidden ctor
Log()
{
// open file ONCE here
}
// Synchronisation primitive - instance variable
// CRITICAL_SECTION or Boost mutex (preferable)
CRITICAL_SECTION cs_;
// File handler: FILE * or std::ofstream
FILE * handler_;
};
回答您的问题:
-
是的,并发日志记录确实需要一个关键部分。
-
是的,日志记录确实会影响性能。
如注释中所述,用于"保护"关键部分的对象必须可由所有线程访问,例如全局变量或singleton。
关于日志记录性能,IO可能成本高昂。一种常见的方法是使用一个日志记录对象来缓冲要记录的消息,并且只在缓冲区已满时进行写入。这将有助于提高性能。此外,考虑具有几个日志级别:DEBUG、INFO、WARNING、ERROR。
CS是保护日志记录的合理方法,是的。为了避免对每个线程的每个调用都施加open/write/close,通常将字符串(如果还没有mallocated/newed,则可能需要将其复制)排队到一个单独的日志线程。阻塞磁盘延迟随后从日志记录调用中得到缓冲。任何延迟写入等优化都可以在日志线程中实现。
或者,正如其他海报所建议的那样,只需使用一个已经实现了所有这些东西的日志框架。
我正在写一个答案,然后一个断路器跳闸了。既然我的答案还在草稿中,我不妨继续下去。与提供singleton类的答案大致相同,但我做得更像C。这一切都在一个单独的源文件中(例如Logging.cpp
)。
static CRITICAL_SECTION csLogMutex;
static FILE *fpFile = NULL;
static bool bInit = false;
bool InitLog( const char *filename )
{
if( bInit ) return false;
bInit = true;
fpFile = fopen( filename, "at" );
InitializeCriticalSection(&csLogMutex);
return fpFile != NULL;
}
void ShutdownLog()
{
if( !bInit ) return;
if( fpFile ) fclose(fpFile);
DeleteCriticalSection(&csLogMutex);
fpFile = NULL;
bInit = false;
}
这些是在您的应用程序入口/出口中调用的。。。至于日志记录,我更喜欢使用变量参数列表,这样我就可以进行printf风格的日志记录。
void writeLog(const char* pMsg, ...)
{
if( fpFile == NULL ) return;
EnterCriticalSection(&csLogMutex);
// You can write a timestamp into the file here if you like.
va_list ap;
va_start(ap, pMsg);
vfprintf( fpFile, pMsg, ap );
fprintf( fpFile, "n" ); // I hate supplying newlines to log functions!
va_end(ap);
LeaveCriticalSection(&csLogMutex);
}
如果您计划在DLL中进行日志记录,则不能使用这种静态方法。相反,您需要使用_fsopen
打开文件并拒绝读/写共享。
如果您希望应用程序崩溃,您可能也希望定期调用fflush
。或者,如果你想从外部实时监控日志,你每次都必须调用它。
是的,关键部分会对性能产生影响,但与写入文件的性能成本相比,这算不了什么。您可以每秒进入关键部分数千次,而无需担心。
- 加快在C++中读取/处理日志文件的速度
- 如何将消息时间戳写入日志文件?
- 分析包含 NMEA 句子的日志文件C++
- 如何从日志文件中抓取状态代码?(在 C++ 中)
- 未创建日志文件
- 尝试使用 EvtSetChannelConfigProperty() 函数更新最大事件日志文件大小时插入的错误值
- 提升日志:文件轮换
- POSIX C/C++日志文件(VEX V5 Brain)
- boost日志文件无法创建sample.log文件
- 哪个更适合从C++写入敏感的日志文件,在文件描述符上写()或文件上的fprintf()?
- 如何编写日志文件,以便可以使用记事本实时读取它以进行C++
- 如何在QT中使用DEBUG对齐日志文件中的数据?
- Qt - 如何在 30 天后删除日志文件,文件名不固定
- Mac OS X:应用程序可以创建日志文件
- 将断言消息写入日志文件
- 检查日志文件以找出 vcredist.exe 安装失败的原因
- C++同时记录到控制台和日志文件
- 无法创建将包含日志文件的文件夹
- (罗)如何使用相对路径保存日志文件
- boost::log关闭日志文件并打开一个新文件