2016-05-25 9 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 (фс, Encoding.Default, 10))

не работает, потому что первая операция записи происходит только тогда, когда около 385 целых чисел ожидания в буфере будет записанный в файл.

  1. Файл будет заполнен, если я закрою запись перед исключением. Но это не очень хороший выбор - я должен писать в файл от 1 до 10 раз в секунду. Не так хорошо открывать и закрывать писателя так часто, не так ли?

  2. Я не могу поймать исключение как этот

    частной статической ничтожной method2() {

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

    }

и все будет в порядке - не завершение работы приложения и файл будут заполнены пакетом. Но это тоже не так - я не могу контролировать, когда и где происходят исключения. Я пытаюсь использовать 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

Вы можете поймать любое исключение в программе, если вы просто перенесите Main method в 'try {} catch {} finally {}' block и в 'finally' block дождитесь окончания работы Thread для завершения выполнения – Fabjan

ответ

1

Flushing поток гарантирует, что все содержимое будет помещено в его основной файл.

Это позаботится о том, чтобы все данные были сохранены после завершения операции и что следующее исключение не приведет к тому, что ваше приложение потеряет данные.

2

Как я понимаю вашу ситуацию, вы предполагаете, что где-то есть ошибка, и процесс может быть прекращен в любое время. Вы хотите сохранить как можно больше данных.

Вы должны позвонить в Flush на номер StreamWriter. Это подтолкнет данные к ОС. Если ваш процесс завершится, данные в конечном итоге будут записаны ОС.

В случае, если вы не можете убедить StreamWriter на самом деле флешем по какой-либо причине, вы можете использовать FileStream и написать на это (псевдокод: fileStream.Write(Encoding.GetBytes(myString))). Затем вы можете очистить FileStream или использовать размер буфера 1.

Конечно, это лучше, если вы не позволите завершить процесс в первую очередь. Это обычно прямо с Task, в отличие от использования необработанных Thread с.

+0

Благодарим вас за ответ. Я отмечаю его как полезный, но отмечаю ответ @ Sidewinder94 как принятый, потому что он был первым. Я также рассмотрю использование задач вместо потоков, но на данный момент фактическое приложение использует потоки, поэтому мне нужно быстрое решение с потоками. – Alex34758