2009-08-25 2 views
2

Можно ли безопасно закрыть System.IO.Stream (или любой из оберток или считывателей) из второго потока?Могу ли я вызвать stream.Close из другого потока?

У меня есть new System.IO.StreamReader(inputStream, Encoding.ASCII); чтение из сети, и я рассматриваю возможность его закрытия из другого потока, закрывая его.

Если это не очень хорошая идея, то какой еще способ заставить поток блокировать при чтении вызова?

ответ

2

Нет, это небезопасно слепо называть метод Close из отдельного потока. Класс Stream не указан как потокобезопасный и вызывает Close из другого потока , в то время как исходный поток использует его приведет к неопределенному поведению.

1

Да, если inputStream считывает из гнезда, то вы можете использовать другой поток, который закроет соединение сокета. Вы должны знать, что блокирующий вызов Read вызовет исключение.

1

Общий подход к очистке опрятно в этой ситуации:

  1. Установить значение, которое указывает на завершение (например, IsDone = true)
  2. Написать некоторые данные в сокет, так что блокировка чтения получает некоторые данные
  3. В потоке, который считывается из гнезда, проверьте, действительно ли значение IsDone истинно перед обработкой прочитанных данных. Если значение IsDone истинно, проигнорируйте данные и закройте поток.

Это должно избегать любых проблем, на которые ссылается Джаред.

+0

уверен, что вы можете сделать только шаг 2, если вам удастся контролировать оба конца соединения сокета, что редко. –

+0

@Mark: Правильно, ну, на самом деле это предполагает, что вы можете писать в поток с той же стороны, что и вы, слушая ... Я мог бы обедать на этом ... –

0

Да, это нормально, чтобы закрыть поток на другой поток, но помните о последствиях этого. Если вы это сделаете, а другой поток использует этот поток, вы получите исключение. Правильное дело - иметь либо событие, либо дескриптор ожидания, что поток, выполняющий чтение, может проверить, должен ли он закрыться. Псевдокод будет выглядеть примерно так: Тема 1. отложить операцию чтения и посмотреть, есть ли данные для чтения.
если данные, прочитайте некоторые данные. если нет, продолжите проверьте ручку ожидания. Если он установлен, закройте его и завершите в противном случае прочитайте еще loop

Тема 2. Если я должен отключить сеть, сообщите, что команда wait еще делает что угодно.

Помните, что если вы находитесь в режиме блокировки, вы получите исключение. Я НИКОГДА НЕ рекомендую использовать блокирующий сокет, нет причин. Мы фактически выполняем (почти) все наши операции async под капотом System.Net, а пути кода синхронизации просто запускают путь к асинхронному коду, а затем блокируются до их завершения.

+0

Jeff: Было бы интересно посмотреть пример кода. leeeroy использует StreamReader - на нем нет асинхронных методов. Означает ли это, что ему нужно будет напрямую читать из сетевого потока, а затем «накачать» значения чтения в текстовый кодировщик? – JMarsch

+0

StreamReader.Read не блокирует, поэтому нет необходимости в методах async (он возвращает -1, если больше данных не существует).Что бы вы сделали, это примерно так: while (someCondition) { if (handle.WaitOne (1)) {// время для удаления потока stream.Close(); stream.Dispose(); myStreamDisposalCompleteHandle.Set() } еще {// Поток по-прежнему нормально использовать данные = stream.Read() // это неблокирующая } в другом потоке: , если (appShouldCloseStreams) { Еогеаспа (streamShouldCloseHandle handle в HandlesThatStreamsHave) handle.Set(); WaitHandle.WaitAll (arayOfAllStreamDisposeCompleteHandles); App.Exit(); –

+0

Просим прощения за использование форматирования. Что происходит в этом коде, так это то, что каждый поток, обрабатывающий поток, имеет две ручки: одну, которую он периодически проверяет, должен ли он закрываться, и тот, который он может использовать, чтобы сигнализировать о том, что он закрыт потоком. Основной поток имеет ссылку на все дескрипторы, которые имеют все потоки потоков. Когда он готов сигнализировать о том, что пришло время кончать, он сигнализирует обо всех остальных потоках, а затем ждет, чтобы они сообщили, что они закончены. Используйте классы ManualResetEvent или AutoResetEvent для своих дескрипторов, WaitHandle - это базовый класс, но он не имеет метода Set. –