Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 来自不同线程的Poco日志行相互覆盖_C++_Multithreading_Logging_Poco Libraries - Fatal编程技术网

C++ 来自不同线程的Poco日志行相互覆盖

C++ 来自不同线程的Poco日志行相互覆盖,c++,multithreading,logging,poco-libraries,C++,Multithreading,Logging,Poco Libraries,我有两个不同的线程,都记录到不同的Poco::WindowsColorConsoleChannel通道 但是,有时消息会交错显示,例如,如果一个线程记录aaaaaaa而另一个线程记录bbbbbbbbbb,则屏幕可能看起来像abbbbaaabbb 线程使用完全不同的记录器对象和不同的通道对象 如果使用默认通道,也会发生同样的情况。颜色控制台通道的问题尤其突出,因为它使颜色看起来像是给错误的线条上色 有没有办法让每一条日志行都是“原子”的 注意:我还没有检查登录到SimpleFileChannel时

我有两个不同的线程,都记录到不同的
Poco::WindowsColorConsoleChannel
通道

但是,有时消息会交错显示,例如,如果一个线程记录
aaaaaaa
而另一个线程记录
bbbbbbbbbb
,则屏幕可能看起来像
abbbbaaabbb

线程使用完全不同的
记录器
对象和不同的通道对象

如果使用默认通道,也会发生同样的情况。颜色控制台通道的问题尤其突出,因为它使颜色看起来像是给错误的线条上色

有没有办法让每一条日志行都是“原子”的

注意:我还没有检查登录到
SimpleFileChannel
时是否会出现相同的问题,但如果是这样,我也需要一个解决方案:)

我已经制定了一个“解决方案”。它有一些缺陷:它可能是在重新发明轮子,可能不是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;
    } ;
struct RC_信号量:Poco::信号量,Poco::RefCountedObject
{
使用Poco::Semaphore::Semaphore;
};
结构信号锁
{
SemaphoreLock(Poco::Semaphore&sem):sem(sem){sem.wait();}
~SemaphoreLock(){sem.set();}
信号量&sem;
};
结构同步通道:Poco::通道,不可复制
{
同步通道(Poco::AutoPtr sem,Poco::AutoPtr dest)
:sem(sem),dest(dest){
虚拟无效日志(const Poco::Message&msg)
{
信号锁(*sem);
dest->log(msg);
}
私人:
Poco::AutoPtr-sem;
Poco::自动发送目的地;
} ;
用法:

// 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);
//输出到控制台的日志通道的同步
auto semConsole=make_AutoPtr(1);
//日志记录通道-主
auto chanMainRaw=make_AutoPtr();
chanMainRaw->setProperty(“调试颜色”、“绿色”);
auto chanMain=make_AutoPtr(semConsole,chanMainRaw);
//线程将使用的通道
auto chanThreadRaw=make_AutoPtr();
chanThreadRaw->setProperty(“调试颜色”、“洋红”);
auto chanThread=make_AutoPtr(semConsole,chanThreadRaw);
//(用于设置过滤器的其他代码可以转到此处)
记录器().setChannel(chanMain);
OtherThread::logger().setChannel(chanThread);

注意
make_AutoPtr
std::make_unique
相同,但与
Poco::AutoPtr
相反,我使用它来避免重复类型名称。

控制台通道日志记录操作受。但是,要提供正确的Unicode文本记录,请在Windows控制台通道上,将UTF-8转换为UTF-16

因此,Application::logger()可能具有默认的WindowsConsoleChannel,而线程具有ConsoleChannel(或其颜色*版本);在任何情况下,您都必须混合使用不同的通道才能看到所描述的效果-尽管目的地相同,但您正在通过不同的通道登录,这些通道受不同的互斥体保护。我认为Poco应该使用一个静态互斥来保护所有控制台通道,以避免类似的问题

考虑到所有这些,即使没有自定义同步方案,上面发布的代码示例也应该可以正常工作

还请注意,每当您登录到同一控制台通道类型时,您的线程将在每次日志操作期间互相等待。为了避免瓶颈,您可以考虑使用.


(简单)FileChannel受保护,因此只要每个线程都登录到自己的文件中,或者它们都通过相同的通道实例登录到相同的文件中,它就不会遇到相同的问题。我从未尝试过后一种方法,但凭直觉,这听起来不太合适。

当然,可以将每次打给记录者的电话都放在一个关键部分,但我希望有更好的方法,例如,日志框架中内置了一些能够处理此问题的东西。您到底是如何创建这些不同的记录器对象的?@Alex线程正在使用
Poco::logger::get(“bla”)
,主应用程序正在使用
Poco::Application
logger()
成员函数,在每种情况下,我都使用
setChannel
Yes连接WindowsColorConsoleChannel,我通过两个不同的WindowsConsoleChannel登录,因为我希望线程使用不同的颜色方案。我想解决同样问题的另一个方法是通过相同的通道进行日志记录,但是为线程添加自定义日志级别,这样我就可以给它们自己的颜色。我将尝试制作一个MCVE,而不仅仅是描述代码。通过相同类型的不同通道进行日志记录是线程安全的。当从两个线程通过不同类型的控制台通道登录时会出现问题。我肯定使用两个WindowsColorConsoleChannel,因为我使用
新建Poco::WindowsColorConsoleChannel
创建它们。我将弥补一个MCVE,因为我必须做一些错误的其他地方,如果这是应该正常工作。