Новый FileStream уже закрыт / удален? - PullRequest
1 голос
/ 13 октября 2010

Я открываю FileStream с FileMode.Open и FileAccess.Read. Вскоре после этого я вызываю функцию для обработки содержимого файла. Я использую Invoke, чтобы сделать вызов, потому что вызов поступает от Thread, а функция должна поместить результаты в Form. Функция принимает любой поток (я называю его с MemoryStream тоже без проблем) и использует XmlTextReader для чтения XML в FileStream, но в редких случаях по неизвестным причинам даже первый Read() бросок ObjectDisposedException и свойство CanRead потока возвращает значение false, если поток уже был закрыт.

В Thread FileStream - это локальная переменная using, поэтому я не думаю, что другие потоки должны быть в состоянии закрыть ее, и я не закрываю ее, пока не вернется Invoke. Не выбрасывается Exceptions, поэтому файл определенно находится там (так как FileNotFoundException) и к нему следует обращаться правильно (поскольку нет UnauthorizedAccessException и IOException).

Как мой FileStream может выглядеть закрытым иногда только после открытия?

(Может иметь значение, что я запускаю свой код на устройстве Windows CE 5 с Compact Framework 3.5 и пока не смог воспроизвести такое же поведение на настольном ПК с XP.)

EDIT: Я знаю, что этот Invoke безобразен, но это само по себе не может быть причиной провала, правда? (И, в большинстве случаев, это совсем не так.)

//the code in the thread
//...
using (FileStream fs = File.Open(assemblyPath + "\\white.xml", FileMode.Open, FileAccess.Read))
{
    mainForm.Instance.Invoke(new DataHandler(mainForm.Instance.handleData), new object[] { fs });
}
//...

//and the handler
public void handleData(Stream stream)
{
    infoPanel.SuspendLayout();
    try
    {
        using (XmlTextReader xml = new XmlTextReader(stream))
        {
            //it doesn't matter what is here
        }
    }
    catch{}
}

Ответы [ 3 ]

1 голос
/ 13 октября 2010

Есть одна причина, по которой я могу думать: рабочий поток был прерван. Это запустит блок finally, сгенерированный с использованием оператора , и закроет файл. Как это могло быть прервано, является второстепенным вопросом. Для свойства потока IsBackground установлено значение true? Программа бомбит необработанное исключение в другом месте и закрывается? Просто догадки конечно.

1 голос
/ 18 августа 2011

Я видел ту же проблему на какой-то встроенной плате (ARM), над которой я работаю.Затем я создал небольшой тест.

Сбой следующего кода (без использования потоков!):

    using (var w = new StreamWriter(File.Create("file.txt"), System.Text.Encoding.UTF8))
    {
        for (int i = 0; i < 1000; i++)
        {
            w.WriteLine("Test");
        }
    }

Однако этот код не дает сбоя:

    using (var w = File.CreateText("file.txt"))
    {
        for (int i = 0; i < 1000; i++)
        {
            w.WriteLine("Test");
        }
    }

Таким образом, я могу только предположить, что основной нативный код обрабатывает текстовые файлы иначе, чем когда вы открываете файл с помощью File.Create ().Затем оба файла записываются в UTF-8, поэтому нет никакой разницы в кодировке.

Кстати: извините, я опоздал на один год с ответом, но я надеюсь, что это кому-нибудь поможет

1 голос
/ 13 октября 2010

Конечно, это ожидаемое поведение.Вы вызываете Invoke, который выполняет вызов другого потока.Затем вызывающий поток продолжает работать, и блок using завершает работу, вызывая Dispose в потоке.Это удаление происходит до того, как вы закончите (и, возможно, перед тем, как начать), используя поток в потоке пользовательского интерфейса.Точное время этих действий будет зависеть от загрузки процессора и некоторых других факторов, но это, безусловно, небезопасно.

Либо не помещайте поток в блок using, либо лучше, пока поток выполняет чтение ипередать результаты в пользовательский интерфейс через Invoke.

EDIT

Как указывает Ганс в комментарии, приведенное выше объяснение должно быть для BeginInvokeвызов, который под вызовами PostMessage.Invoke, с другой стороны, использует SendMessage.Оба, вероятно, используют некоторые shenanigans WM_COPYDATA (я не смотрел, чтобы видеть), чтобы упорядочить данные.

Вызов Invoke должен выполнять весь обработчик, который вы опубликовали, хотя поведение вы видитеуказывает на обратное.Исходя из кода, который вы опубликовали, у нас нет реального способа определить, что закрывает поток.

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

...