2009-06-30 41 views
2

所以我有一個靜態類,應該用作日誌文件管理器,能夠將「消息」(字符串)添加到隊列對象,並將消息推送到文件。麻煩的是,許多不同的線程應該排隊,並且作者也需要異步。目前,當我插入隊列時,我還檢查是否寫作者(布爾檢查),如果不是,我設置了布爾然後開始寫入,但我得到了關於文件訪問的間歇性IO異常,然後有時候寫作行爲會更加奇怪。多線程文件寫隊列

有人想幫我一下嗎?

回答

2

聽起來像隊列正在驅動文件寫入操作。我建議您反轉控制關係,以便寫入者驅動進程並檢查隊列是否工作。

實現此目的的最簡單方法是向寫入程序添加輪詢機制,在該寫入程序中它會定期檢查隊列的工作情況。

或者,您可以創建一個可觀察的隊列類,在隊列從空過渡時通知訂閱者(作者):訂閱作者可以開始工作。 (此時,作者還應退訂隊列的廣播,或以其他方式更改對隊列警報的反應方式。)

作業完成後,作者將檢查隊列以進行更多工作。如果沒有其他工作要做,它會進入睡眠狀態並繼續輪詢或進入睡眠狀態並重新訂閱隊列的警報。

由於Irwin noted in his answer,你還需要使用由Queue類的Synchronized方法提供的線程安全的包裝或手動如果將多個線程從中讀取和寫入到它(as in SpaceghostAli's example)同步訪問你的Queue

2

您應該同步您的隊列。讓多個線程發送到隊列並從隊列中讀取單個線程並寫入文件。

public void Log(string entry) 
{ 
    _logMutex.WaitOne(); 
    _logQueue.Enqueue(entry); 
    _logMutex.ReleaseMutex(); 
} 

private void Write() 
{ 
    ... 
    _logMutex.WaitOne(); 
    string entry = _logQueue.Dequeue(); 
    _logMutex.ReleaseMutex(); 

    _filestream.WriteLine(entry); 
    ... 
} 
1

如果你不想調整你的代碼大大就像我在我的其他回答表明,你可以試試這個,它假設你LogManager類有:

  • 靜態線程安全隊列,_SynchronizedQueue
  • 靜態對象寫入時來鎖定,_WriteLock

並且這些方法:

public static void Log(string message) { 
    LogManager._SynchronizedQueue.Enqueue(message); 
    ThreadPool.QueueUserWorkItem(LogManager.Write(null)); 
} 

// QueueUserWorkItem accepts a WaitCallback that requires an object parameter 
private static void Write(object data) { 
    // This ensures only one thread can write at a time, but it's dangerous 
    lock(LogManager._WriteLock) { 
     string message = (string)LogManager._SynchronizedQueue.Dequeue(); 
     if (message != null) { 
      // Your file writing logic here 
     } 
    } 
} 

只有一個問題:上述Write方法中的鎖定語句將保證一次只能有一個線程寫入,但這是危險的。嘗試寫入文件時會出現很多錯誤,並且您不希望無限期地保持(阻止)線程池線程。因此,你需要使用一個同步對象,可以讓你指定超時,如Monitor,並重寫你Write方法是這樣的:

private static void Write() { 
    if (!Monitor.TryEnter(LogManager._WriteLock, 2000)) { 
     // Do whatever you want when you can't get a lock in time 
    } else { 
     try { 
     string message = (string)LogManager._SynchronizedQueue.Dequeue(); 
     if (message != null) { 
      // Your file writing logic here 
     } 
     } 
     finally { 
     Monitor.Exit(LogManager._WriteLock); 
     } 
    } 
} 
1

讓我在不同的層面解決的問題:

如果你正在編寫一個商業應用程序,那麼你應該把重點放在業務邏輯部分而不是基礎代碼上,如果這個代碼已經可用,測試並部署到多個生產站點(照顧你的NFR),那麼更是如此。

我確定你知道伐木框架的存在ks像log4net和其他http://csharp-source.net/open-source/logging

在您推出自己的記錄器之前,您是否給過這些機會?

將此選項添加到您正在撰寫的企業的技術架構師,並看到她的想法。

乾杯