来自不同线程的Poco日志行相互覆盖
Poco log lines from different thread overwrite each other
我有两个不同的线程,它们都记录到单独的Poco::WindowsColorConsoleChannel
通道。
然而,有时消息看起来是交错的,例如,如果一个线程记录aaaaaaa
,而另一个线程则记录bbbbbbbb
,则屏幕可能看起来像abbbbbaaaaaabbb
。
线程使用完全不同的Logger
对象和不同的通道对象。
如果使用默认通道,也会发生同样的情况。颜色控制台通道的问题尤其明显,因为它使颜色看起来像是错误的线条被着色了。
有没有一种方法可以使每条日志行成为"原子"?
注意:我还没有检查登录到SimpleFileChannel
时是否会出现同样的问题,但如果是这样,那么我也需要一个解决方案:)
ConsoleChannel日志记录操作由静态FastMutex保护。但是,为了提供正确的Unicode文本日志记录,在Windows上,控制台通道默认为WindowsConsoleChannel,它将UTF-8转换为UTF-16。
因此,Application::logger()可能具有默认的WindowsConsoleChannel,而线程具有ConsoleChannnel(或其Color*版本);在任何情况下,您都必须混合使用不同的通道才能看到您所描述的效果——尽管目的地是相同的,但您是通过不同的通道进行日志记录的,这些通道由不同的互斥体保护。我认为Poco用一个静态互斥来保护所有控制台通道以避免类似的问题是有意义的。
考虑到所有这些,即使没有自定义同步方案,您在上面发布的代码示例也应该可以正常工作。
还要注意,每当您登录到相同的控制台通道类型时,您的线程都会在每次日志操作期间相互等待。为了避免瓶颈,您可以考虑使用AsyncChannel。
(简单)FileChannel由非静态FastMutex保护,因此只要每个线程都登录到自己的文件中,或者它们都通过同一个通道实例登录到同一个文件,它就不会遇到同样的问题。我从未尝试过后者,但凭直觉,这听起来不是正确的做法
我已经制定了一个"解决方案"。它有一些缺陷:它可能是在重新发明轮子,它可能不适合Poco(我对Poco还很陌生),我担心如果在线程或应用程序关闭期间抛出异常,可能会出现死锁。
但目前看来是可行的。
在头文件中:
struct RC_Semaphore: Poco::Semaphore, Poco::RefCountedObject
{
using Poco::Semaphore::Semaphore;
};
struct SemaphoreLock
{
SemaphoreLock(Poco::Semaphore &sem): sem(sem) { sem.wait(); }
~SemaphoreLock() { sem.set(); }
Poco::Semaphore &sem;
};
struct SynchronizingChannel: Poco::Channel, noncopyable
{
SynchronizingChannel(Poco::AutoPtr<RC_Semaphore> sem, Poco::AutoPtr<Poco::Channel> dest)
: sem(sem), dest(dest) {}
virtual void log(const Poco::Message& msg)
{
SemaphoreLock lock(*sem);
dest->log(msg);
}
private:
Poco::AutoPtr<RC_Semaphore> sem;
Poco::AutoPtr<Poco::Channel> dest;
} ;
用法:
// Synchronization for log channels outputting to console
auto semConsole = make_AutoPtr<RC_Semaphore>(1);
// Logging channel - main
auto chanMainRaw = make_AutoPtr<Poco::WindowsColorConsoleChannel>();
chanMainRaw->setProperty("debugColor", "green");
auto chanMain = make_AutoPtr<SynchronizingChannel>(semConsole, chanMainRaw);
// Channel that will be used by thread
auto chanThreadRaw = make_AutoPtr<Poco::WindowsColorConsoleChannel>();
chanThreadRaw->setProperty("debugColor", "magenta");
auto chanThread = make_AutoPtr<SynchronizingChannel>(semConsole, chanThreadRaw);
// (other code to set up filters can go here)
logger().setChannel(chanMain);
OtherThread::logger().setChannel(chanThread);
注:。make_AutoPtr
与std::make_unique
相同,但使用了Poco::AutoPtr
,我使用它来避免重复类型名称。
- 使用ios:ate写入到流会覆盖现有文件
- EvtExportLogneneneba API正在将远程计算机的事件日志保存到远程PC本身.如何将其保存到主机
- 我可以重新分配/覆盖std::字符串吗
- 叮叮当当在修复时插入多个"覆盖"说明符
- 谷歌模拟和覆盖关键字
- TMap::Emplace() 在应用现有密钥时会覆盖吗?
- 此测试()中发生了什么意外过程?为什么总是覆盖 ch[0 1 2..]?
- 使用子类覆盖基类中定义的函数
- 是否可以配置提升日志刷新?
- 当覆盖存在时调用基本虚拟"binded to object"函数
- C++指针在 for 循环中被覆盖
- 跟踪日志中的T.11803()是什么意思?
- "main"函数堆栈中的对象在第一个任务运行时被覆盖 (FreeRTOS)
- 加快在C++中读取/处理日志文件的速度
- 如何将消息时间戳写入日志文件?
- 为什么我的全局 new() 覆盖被绕过了?
- 被覆盖的函数不会反映在基类中,这是正常行为吗?
- C++找出覆盖同一行的数组
- 来自不同线程的Poco日志行相互覆盖
- 如何不覆盖文件,C++日志记录