2016-05-25 32 views
2

這是一個簡單的例子如何保證在多線程中使用異常寫入文件?

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      new Thread(() => Method1()).Start(); 
      new Thread(() => Method2()).Start(); 
      Console.Read(); 
     } 

     private static void Method1() 
     { 
      using (StreamWriter sw = new StreamWriter(@"h:\data.txt")) 
      { 
       int i = 100000000; 
       while (true) 
       { 
        Thread.Sleep(100); 
        sw.WriteLine(i); 
        i++; 
       } 
      } 
     } 

     private static void Method2() 
     { 
      Thread.Sleep(6000); 
      throw null; 
     } 
    } 
} 

的StreamWriter如果發生異常太早,在另一個線程不會將數據寫入到文件中。發生異常時,文件data.txt爲空。

我打這種情況一點,發現了一堆解決方法:

  1. 如果我增加了異常的線程睡眠間隔(和著作之間減少間隔成文件),該文件將充滿數據。這不是一個選擇,因爲我不知道什麼時候發生異常。

  2. 由於以前的解決方法,我可以減少流編寫器的緩衝區大小。但它似乎不工作,如果我把它設置得太小 - 例如,此代碼

    FileStream fs = new FileStream(@「h:\ data.txt」,FileMode.Create);

    使用(StreamWriter的SW =新的StreamWriter(FS,Encoding.Default,10))

不起作用,因爲只出現在第一寫入操作時約385的整數中的緩衝器正在等待寫入文件。

  1. 如果在發生異常之前關閉寫入器,文件將被填充。但這不是一個好的選擇 - 我必須每秒寫入1到10次的文件。如此頻繁地打開和關閉作家並不是一個好主意,是嗎?

  2. 我能趕上這樣的

    私有靜態無效方法2)異常( {

    try 
    { 
        Thread.Sleep(6000); 
        throw null; 
    } 
    catch 
    { 
        Console.WriteLine("Exception!"); 
    } 
    

    }

一切就會OK - 沒有應用程序終止和文件將被填充包裝。但情況並非如此 - 我無法控制發生異常的時間和地點。我試圖在任何地方使用try-catch,但我可能會錯過一些東西。

所以情況是:StreamWriter的緩衝區未滿,在另一個線程中發生異常並且未捕獲,因此應用程序將被終止。如何不丟失這些數據並將其寫入文件?

+2

您是否嘗試'刷新'流而不是關閉它。這應該照顧到保存數據到文件,同時讓流打開並接受更多的數據 – Sidewinder94

+0

也就是說,我會建議你檢查一下['lock'](https://msdn.microsoft.com/en- us/library/c5kehkcz.aspx)關鍵字和['Mutex'](https://msdn.microsoft.com/en-us/library/system.threading.mutex(v = vs.110).aspx)對象存在以解決這些併發問題 – Sidewinder94

+0

如果您簡單地在'try {} catch {} finally {}'塊中並在'finally'塊中封裝Main方法等待工作Thread可以完成執行 – Fabjan

回答

1

Flushing該流將確保將其所有內容都推送到其底層文件中。

這會照顧到在完成操作後保存所有數據,並且以下異常不會使應用程序數據鬆動。

2

正如我瞭解您的情況,您假設某處存在錯誤,並且該進程可能隨時終止。您希望儘可能多地保存數據。

您應該可以撥打StreamWriter致電Flush。這會將數據推送到操作系統。如果您的進程終止,數據最終將由操作系統寫入。

如果您不能說服StreamWriter因某種原因實際刷新,您可以使用FileStream並寫入(僞代碼:fileStream.Write(Encoding.GetBytes(myString)))。然後可以刷新FileStream或使用1的緩衝區大小。

當然,最好是防止進程被終止。這通常是直接與Task而不是使用原始Thread s。

+0

謝謝你的回答。我將其標記爲有用,但將@ Sidewinder94的答案標記爲已接受,因爲他是第一個。我也會考慮使用任務而不是線程,但現在實際的應用程序使用線程,所以我需要線程的快速解決方案。 – Alex34758

相關問題