2012-05-31 13 views
3

全部兩個線程 - Console.out的兩個流

我有一個庫,不是我的,所以那麼它不能被修改。 這個庫有兩個方法,我們稱它們爲Method_1()和Method_2()。 在這些方法被稱爲Console.WriteLine( 「...」)

我有一類

public class CustomBackgroundWorker: BackgroundWorker 
{ 
     private readonly StringBuilder logBuilder; 

     public CustomBackgroundWorker() 
     { 
      logBuilder = new StringBuilder(); 
      TextWriter outStream = new StringWriter (logBuilder); 
      Console.SetOut (outStream); 
     } 

     public string GetLogs() 
     { 
      return logBuilder.ToString(); 
     } 
} 

它創建這個類的兩個實例。每個實例從庫中執行方法。但輸出僅保存在一個流中,因爲SetOut()方法在全局工作。 是否有可能將不同線程的輸出重定向到獨立的流?

Thx

回答

4

您要做的事並不容易。 Console.WriteLine()et al are static,因爲它們是共享的;任何調用這些方法的線程都會向標準輸出流寫入標準輸出流。

將輸出分割成單獨文件的最簡單方法是創建自己的TextWriter,該文件包裝多個輸出文件,並將其設置爲標準輸出。然後,讓每個線程註冊您的TextWriter,指定所需的輸出文件。每當調用進入編寫器時,它就會查看哪個線程進行了調用,然後寫入適當的文件。

這顯然需要一些工作才能得到正確的結果(因爲有許多競爭條件和資源共享問題是可能出現的問題),但可以讓您按照自己的意願去做。

編輯:下面是一個這樣的作者可能看起來像什麼樣子,以及它如何使用。 這個類是不完整的(例如,它目前僅支持WriteLine(),對於string s),並且也可能存在其他錯誤。

public class ThreadAwareStreamWriter : TextWriter 
{ 
    private ConcurrentDictionary<int, TextWriter> threadWriterMap; 
    private TextWriter defaultWriter; 

    public ThreadAwareStreamWriter() 
    { 
     this.threadWriterMap = new ConcurrentDictionary<int, TextWriter>(); 
     this.defaultWriter = Console.Out; 
    } 

    public TextWriter RegisterThreadWriter(TextWriter threadWriter) 
    { 
     int threadId = Thread.CurrentThread.ManagedThreadId; 

     TextWriter oldWriter; 
     this.threadWriterMap.TryGetValue(threadId, out oldWriter); 
     this.threadWriterMap[threadId] = threadWriter; 

     return oldWriter; 
    } 

    public void DeregisterThread() 
    { 
     TextWriter threadWriter; 
     if (this.threadWriterMap.TryRemove(Thread.CurrentThread.ManagedThreadId, out threadWriter)) 
     { 
      threadWriter.Close(); 
     } 
    } 

    public override Encoding Encoding 
    { 
     get 
     { 
      TextWriter threadWriter; 
      if (this.threadWriterMap.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadWriter)) 
      { 
       return threadWriter.Encoding; 
      } 

      return this.defaultWriter.Encoding; 
     } 
    } 

    public override void WriteLine(string value) 
    { 
     TextWriter threadWriter; 
     if (this.threadWriterMap.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadWriter)) 
     { 
      threadWriter.WriteLine(value); 
      return; 
     } 

     if (this.defaultWriter != null) 
     { 
      this.defaultWriter.WriteLine(value); 
     } 
    } 
} 

的樣本程序:

public static void Main(string[] args) 
{ 
    ThreadAwareStreamWriter writer = new ThreadAwareStreamWriter(); 
    Console.SetOut(writer); 

    Thread t = new Thread(o => 
    { 
     ThreadAwareStreamWriter tWriter = (ThreadAwareStreamWriter)o; 
     tWriter.RegisterThreadWriter(new StreamWriter(File.Open("test.txt", FileMode.Create, FileAccess.ReadWrite))); 
     Console.WriteLine("Hello from another thread"); 

     tWriter.DeregisterThread(); 
    }); 

    t.Start(writer); 

    Console.WriteLine("Hello"); 
    Console.ReadLine(); 
} 

這會打印出「你好」到控制檯,以及「你好從另一個線程」到文件「的test.txt」。

+0

+1好的答案。但是它可能會(可能)更好地使用Thread dataslots。 – leppie

+0

@leppie是的,我想管理的ID可以被重用,如果被終止的線程忘記調用'DeregisterThread()',這可能會導致意外的行爲。就像我說的,「這個代碼可能有bug」:) – dlev