2015-04-30 47 views
3

我有兩個不同的線程,它們都記錄到單獨的Poco::WindowsColorConsoleChannel通道。來自不同線程的Poco日誌行互相覆蓋

然而有時候這些消息是交錯的,例如,如果一個線程記錄aaaaaaa而另一個記錄bbbbbbbb那麼屏幕可能看起來像abbbbbaaaaaabbb

線程正在使用完全不同的Logger對象和不同的通道對象。

如果使用默認通道,則會發生同樣的情況。顏色控制檯通道的問題尤其明顯,因爲它使顏色看起來像錯誤的線條被着色。

有沒有辦法讓每個日誌行'原子'?

注:我還沒有檢查,看看是否記錄到SimpleFileChannel時出現同樣的問題,但如果是這樣,那麼我會需要太:)

+0

當然,在關鍵部分中可以將每次調用都打包到記錄器中,但我希望有更好的東西,內置到日誌框架中的一些東西能夠處理這個問題。 –

+0

你是如何創建這些不同的記錄器對象? – Alex

+0

@Alex線程使用'Poco :: Logger :: get(「bla」)',主應用程序使用'Poco :: Application'的'logger()'成員函數,在每種情況下,我都通過附加WindowsColorConsoleChannel使用'setChannel' –

回答

0

的解決方案我已經作出了「解」。它有一些缺陷:它可能重新發明了輪子,它可能不是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); 

NB。 make_AutoPtrstd::make_unique相同,但與Poco::AutoPtr相反,我使用它來避免必須複製類型名稱。

1

ConsoleChannel日誌記錄操作受static FastMutex保護。但是,爲了在Windows上提供正確的Unicode文本日誌記錄,ConsoleChannel defaults to WindowsConsoleChannel將UTF-8轉換爲UTF-16。因此,Application :: logger()可能具有默認的WindowsConsoleChannel,而線程具有ConsoleChannel(或其Color *版本);在任何情況下,您必須混合使用不同的頻道才能看到您所描述的效果 - 儘管目標位置相同,但您仍然通過不同的頻道進行日誌記錄,這些頻道受不同的互斥鎖保護。我認爲Poco可以通過一個靜態互斥鎖保護所有控制檯通道,以避免這樣的問題。

考慮到所有這些,即使沒有自定義同步方案,上面發佈的代碼示例也應該可以正常工作。

還要注意的是,無論您何時登錄到相同的控制檯通道類型,您的線程都將在每次日誌操作期間等待對方。爲了避免瓶頸,你可以考慮使用AsyncChannel

(簡單)FileChannel受non-static FastMutex保護,所以只要每個線程都登錄到它自己的文件或它們都通過相同的通道實例登錄到同一個文件,它就不會遭受同樣的問題。我從來沒有嘗試過後者,但直覺上聽起來不像是正確的事情。

+0

是的,我正在通過兩個不同的WindowsConsoleChannel進行日誌記錄,因爲我希望線程使用不同的配色方案。我想同樣的問題的另一個解決方案是登錄相同的渠道,但爲線程添加自定義日誌級別,以便我可以給他們自己的顏色。我會嘗試製作一個MCVE,而不是僅僅描述代碼。 –

+0

記錄同一類型的不同通道是線程安全的。從兩個線程通過不同類型的控制檯通道登錄時會發生此問題。 – Alex

+0

我肯定使用兩個WindowsColorConsoleChannel,因爲我使用'新的Poco :: WindowsColorConsoleChannel'創建它們。我會組成一個MCVE,因爲如果這應該能正常工作,我必須在其他地方做一些錯誤的事情。 –