如何保证在多线程中使用异常写入文件?

时间:2016-05-25 12:13:31

标签: c# multithreading exception streamwriter

这是一个简化的例子

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 = new StreamWriter(fs,Encoding.Default,10))

  3. 不起作用,因为只有当大约385个整数在缓冲区中等待写入文件时才会发生第一次写操作。

    1. 如果在异常发生之前关闭编写器,将填写文件。但这不是一个好选择 - 我必须每秒写入1到10次文件。如此频繁地打开和关闭作者不是一个好主意,是吗?

    2. 我可以像这样抓住异常

      private static void Method2() {

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

      }

    3. 一切都会好 - 没有应用程序终止和文件将逐包填写。但事实并非如此 - 我无法控制异常发生的时间和地点。我尝试在任何地方使用try-catch,但我可能会错过一些东西。

      所以情况是:StreamWriter的缓冲区未满,在另一个线程中发生异常并且未被捕获,因此应用程序将被终止。如何不丢失这些数据并将其写入文件?

2 个答案:

答案 0 :(得分:2)

根据我了解您的情况,您假设某处存在错误,并且该过程可能随时终止。您希望尽可能多地保存数据。

您应该可以在Flush上致电StreamWriter。这会将数据推送到操作系统。如果您的进程终止,则数据最终将由操作系统写入。

如果您因某种原因无法说服StreamWriter实际刷新,可以使用FileStream并写入(伪代码:fileStream.Write(Encoding.GetBytes(myString)))。然后,您可以刷新FileStream或使用1的缓冲区大小。

当然,如果您阻止该流程首先被终止,那么它是最好的。与使用原始Task相反,Thread通常是直截了当的。

答案 1 :(得分:1)

Flushing流将确保将其所有内容都推送到其底层文件中。

这样可以确保在完成操作后保存所有数据,并且以下异常不会使您的应用程序丢失数据。