Microsoft.NET и многоядерный процессор Doom - PullRequest
2 голосов
/ 19 ноября 2008

Правильный вопрос

Кто-нибудь сталкивался с этим исключением на одноядерном компьютере?

The I/O operation has been aborted because of either a thread exit or an application request.

Некоторый контекст

В системе с одним процессором одновременно выполняется только одна инструкция MSIL, независимо от потоков. Между операциями среда выполнения выполняет свою служебную работу.

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

Интересно, что HyperThreaded Pentiums не проявляют проблему.

У меня был пример кода, который отлично работал на одном ядре и шелестел на многоядерном процессоре. Это где-то где-то, но я все еще пытаюсь найти это. Суть его заключалась в том, что, когда он был реализован как шаблон Visitor, он шелушился после непредсказуемого количества итераций, но перемещение метода в объект, с которым работал посетитель, приводило к исчезновению проблемы.

Для меня это говорит о том, что в фреймворке есть какая-то внутренняя хеш-таблица для разрешения ссылок на объекты, и в многоядерной системе существует условие гонки в отношении доступа к этому.

У меня также есть код, использующий APM для обработки последовательных сообщений. Раньше он периодически отображал синий экран в драйвере виртуального компорта для моего последовательного USB-адаптера, но я исправил это, выполняя Thread.Sleep(0) после каждого Stream.EndRead(IAsyncResult)

Через случайные интервалы, когда вызывается AsyncCallback, который я предоставляю Stream.BeginRead(...), и обработчик пытается вызвать Stream.EndRead(IAsyncResult), он выдает IOException, заявляя, что The I/O operation has been aborted because of either a thread exit or an application request.

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

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

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

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


Было высказано предположение, что проблема скорее в моем коде, чем в фреймворке.

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

Вариант B Я не так проверял, потому что у меня больше нет одноядерных систем. Поэтому я повторяю вопрос: кто-нибудь видел это исключение на одноядерной платформе?

К сожалению, никто не может подтвердить мое подозрение, только опровергнуть его.

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

Если вы знаете способ прикрепления приложения .NET к одному ЦП, это было бы очень удобно для выяснения этого. --- Спасибо за предложение VM. Я сделаю именно это, хороший звонок.

Ответы [ 5 ]

2 голосов
/ 19 ноября 2008

В настоящее время я переписываю весь стек передачи файлов, который используется в нашем приложении. Из разговоров с другими работниками я знаю, что это было своего рода работа пару лет назад, когда в производстве использовались одноядерные ноутбуки и медленные соединения. Теперь все перешли на двухъядерные процессоры и Интернет со скоростью вращения, и все программное обеспечение показывает непредсказуемые результаты.

Итак, когда я начал больше изучать код, я обнаружил, что человек, который его разработал, не имел ни единого представления о том, как правильно писать многопоточный код . Вся «синхронизация» выполняется с помощью Thread.Sleep ()! Управление потоками осуществлялось по принципу «запусти и забудь». Кто-то хочет остановить поток? Thread.Abort ()! Проклятье! Это сюрприз, черт возьми, работал вообще.

Моя точка зрения - иди и проверь свой код , и, если ты работаешь с каким-то нестандартным оборудованием, код их драйверов. Проблема там, а не в .NET, Win32 или где-то еще.

2 голосов
/ 19 ноября 2008

Синие экраны возникают не только из-за ошибок в приложениях или фреймворках. Синие экраны нуждаются в «помощи» из режима ядра. Одна из ваших проблем - неисправный драйвер, независимо от того, в какую «эпоху» был закодирован неисправный драйвер.

Что касается возможности закрытия одним потоком порта, в то время как другой поток все еще использует его, я думаю, это может быть связано с некоторыми известными ошибками в ведении фреймворка. Я думаю, что эти ошибки не зависят от количества ядер, но частота появления этих ошибок может увеличиться, когда будет больше ядер. Попробуйте добавить вызов GC.KeepAlive, чтобы инфраструктура не удаляла ваш порт слишком рано.

2 голосов
/ 19 ноября 2008

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

Дополнение: Чтобы ответить на ваш вопрос о том, как ограничить ваше приложение одним процессором, вам необходимо установить привязку процесса к одному процессору. Смотрите эту ссылку . Вы также можете сделать это после того, как ваш процесс запущен с помощью диспетчера задач (щелкните правой кнопкой мыши процесс в диспетчере задач и выберите «Установить сходство ...»)

1 голос
/ 19 ноября 2008

Я полностью теряю здесь слова. Вы говорите, что ваш код работает на двухъядерных компьютерах, и вы подозреваете MS для этого !!!

В наши дни у каждой машины есть два или даже четыре ядра. Если в среде .net возникали какие-либо серьезные проблемы с работой с двумя ядрами, то почему живые мессенджеры, живые писатели и многие другие толстые приложения .net часто ломаются. Я считаю, что студии управления SQL Server 2K5 и 2K8 также находятся в .net. Вся реализация System.Web находится в самом C #. Весь дизайнер оркестровки Biztalk находится в .net

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

Вы пробовали SOS? Попробуйте сделать это ... Я не знаю много, но Google для этого, и вы, безусловно, получите хорошие ресурсы по использованию SOS.

В качестве окончательного решения откройте дело с поддержкой MS. Вы должны быть немного терпеливы с ними, потому что сначала они начнут со всех глупых вопросов :). Удачи.

1 голос
/ 19 ноября 2008

До Vista любой асинхронный ввод-вывод, который выполнялся, когда поток, выдавший его, завершается. Это приводит к ошибке, о которой вы сообщаете, т. Е.

Операция ввода-вывода была прервана из-за выхода из потока или запрос заявки.

Я не уверен, относится ли это каким-либо образом к вашему вопросу, но вы выполняете асинхронные операции из потока, который может завершиться до завершения операций?

...