Асинхронное чтение сокетов: исходящий поток не должен быть закрыт - что делать? - PullRequest
6 голосов
/ 30 августа 2011

У меня есть NetworkStream, который я читаю асинхронно (используя async / await)

await Task<int>.Factory.FromAsync((cb, state) => stream.BeginRead(buffer, offset, readLen - offset), stream.EndRead, null);

К сожалению, иногда возникает исключение io: «Операция ввода-вывода была прервана из-за выхода из потока или запроса приложения».

Я считаю, что выполнил требование, задокументированное в Socke.EndReceive: http://msdn.microsoft.com/en-us/library/w7wtt64b.aspx. Который гласит:

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

Поскольку асинхронный метод выполняется в планировщике по умолчанию, это требование не может быть обеспечено.

Есть ли способ обойти это? Нужно ли запускать отдельный поток для запуска ввода-вывода?

С наилучшими пожеланиями, Дирк

Ответы [ 3 ]

3 голосов
/ 22 декабря 2011

Я задал тот же вопрос на форуме Parallelextensions:

http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/d116f7b0-c8ee-4ce4-a9b8-4c38120e45a4

По сути, ThreadPool не будет останавливать потоки, ожидающие асинхронного ввода-вывода.Поэтому до тех пор, пока запускается операция с сокетом в ThreadPool, эта проблема не должна возникать.

1 голос
/ 17 сентября 2011

Я бы рекомендовал использовать выделенные потоки ввода / вывода, которые никогда не завершаются. Это то, что делает много реального кода.

Один из лучших способов сделать это состоит в том, чтобы петли потоков вокруг GetQueuedCompletionStatus. Если вам нужно, чтобы один из потоков ввода-вывода выполнил операцию ввода-вывода, вызовите PostQueuedCompletionStatus или QueueUserAPC, чтобы поток ввода-вывода разместил работа.

ВНИМАНИЕ : Вы должны обрабатывать случай, когда эти операции не выполняются. QueueUserAPC, например, может потерпеть неудачу, если слишком много APC уже поставлено в очередь.

0 голосов
/ 31 августа 2011

Вы можете использовать самый старый трюк в книге. Заставьте свою нить спать в бесконечном цикле

while(true) {
    Threading.Sleep(TimeSpan.FromSeconds(1); 
}

Обратите внимание, что я написал вышеупомянутый код только из моей головы. Не проверял его в Visual Studio, так как сейчас я работаю на своем Mac.

Также вам нужно будет что-то написать для выхода из потока, когда это необходимо, но это будет зависеть от того, как работает ваше приложение.

...