Обнаружена ошибка ContextSwitchDeadlock в C #

80

Я запускаю приложение C # и во время выполнения получаю следующую ошибку:

CLR не смогла перейти из COM-контекста 0x20e480 в COM-контекст 0x20e5f0 в течение 60 секунд. Поток, которому принадлежит целевой контекст / квартира, скорее всего, либо выполняет ожидание без перекачки, либо обрабатывает очень длительную операцию без перекачки сообщений Windows. Эта ситуация обычно отрицательно сказывается на производительности и может даже привести к тому, что приложение перестает отвечать или использование памяти постоянно накапливается с течением времени. Чтобы избежать этой проблемы, все потоки однопоточного подразделения (STA) должны использовать примитивы ожидания перекачки (такие как CoWaitForMultipleHandles) и регулярно перекачивать сообщения во время длительных операций.

Может ли кто-нибудь помочь мне с проблемой здесь?

Большое спасибо.

убийца
источник

Ответы:

123

Основной поток вашей программы был занят выполнением кода в течение минуты. Он не выполняет свои обычные обязанности, прокачивая цикл сообщений. Это незаконно, когда вы используете COM-серверы в рабочем потоке: вызовы их методов не могут быть отправлены, пока ваш основной поток снова не перейдет в режим ожидания.

Это должно быть хорошо видно, ваш интерфейс должен быть мертвым, как дверной гвоздь. Windows должна была заменить ваше главное окно призраком, который отображает «Не отвечает». Закрытие окна не сработает, события щелчка не действуют.

Все, что делает ваш основной поток, должно выполняться рабочим потоком. BackgroundWorkerКласс хорош для этого, вы найдете много помощи использования в статье MSDN Library для него. Используйте Debug + Break All, Debug + Windows + Threads, если вы не знаете, что делает основной поток.

Еще одна возможная причина: обязательно установите пакет обновления 1, если вы используете RTM-версию VS2005.

Ганс Пассан
источник
5
+1 за объяснение того, что такой рабочий элемент должен быть перемещен во вторичный поток, таким образом, решение о том, как избежать этой ошибки (а не только то, что вызывает ошибку).
JYelton
2
Интересно, что я видел, как несколько других приложений, созданных собственными силами, зависали намного дольше моего, но я получил это сообщение об ошибке, хммм.
Coops
Документация MSDN: contextSwitchDeadlock MDA msdn.microsoft.com/en-us/library/ms172233%28v=vs.110%29.aspx
D_Bester
1
Спасибо за подробное объяснение. Я использовал асинхронные функции, которые теперь имеют смысл. Итак, насколько я понимаю, очень важно управлять новым потоком для длительных операций, особенно при использовании COM.
Энтони Мейсон,
50

Чтобы узнать, какая операция блокирует переключение контекста и вызывает отображение MDA contextSwitchDeadlock , можно использовать следующие шаги. Обратите внимание, что я буду иметь в виду Visual Studio 2012.

  1. Воспроизведите ошибку. Это может быть связано с методом проб и ошибок.
  2. В отображаемом помощнике по управляемой отладке нажмите «ОК», а не «Продолжить».
  3. Убедитесь, что панель инструментов «Место отладки» активна, щелкнув правой кнопкой мыши область закрепления панели инструментов и выбрав «Место отладки». Вы должны увидеть раскрывающийся список с надписью «Тема» на панели инструментов, если он активен.
  4. Выбранный элемент в раскрывающемся списке «Поток» должен быть потоком, отличным от основного, поскольку это будет фоновый поток, который жалуется, что основной поток отвлекает все внимание. Выберите основной поток в раскрывающемся списке.
  5. Теперь вы должны увидеть код, который блокирует переключение контекста в редакторе кода.

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

В отладчике Visual Studio

  1. Вы можете отключить MDA непосредственно в диалоговом окне MDA, которое отображается при возникновении ошибки, сняв флажок «Прерывание при возникновении этого типа исключения».
  2. С диалоговым окном «Параметры исключения», используя приведенные ниже инструкции из MSDN .

... в меню "Отладка" выберите "Исключения". (Если в меню «Отладка» нет команды «Исключения», щелкните «Настроить» в меню «Инструменты», чтобы добавить ее.) В диалоговом окне «Исключения» разверните список «Помощники по управляемой отладке» и снимите флажок «Выброшено» для отдельного MDA.

Вне отладчика Visual Studio

  1. Ключ реестра (для всей машины, затронуты все MDA)
  2. Переменная среды (для всей машины, можно указать MDA)
  3. Параметры конфигурации приложения (область применения, можно указать MDA)

Примечание. Один из первых двух параметров должен иметь значение 1, чтобы третий работал.

В моем случае проблема заключалась в вызове ObjectContext.SaveChanges () в Entity Framework в консольном приложении. После применения атрибута MTAThreadAttribute к Main()методу исключение ContextSwitchDeadlock больше не возникало . К сожалению, я не уверен во всех последствиях этого изменения.

Скотт Манро
источник
2
Проголосуйте за четкое объяснение поиска кода, который блокирует процесс.
Guillaume Schuermans
10

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

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

Франси Пенов
источник
4

В некоторых случаях:
Отладка -> Исключения -> Управляемые помощники отладки
и снятие отметки с элемента ContextSwitchDeadlock.

Эхсан Заргар Эршади
источник
5
Да, но когда вы пишете одноразовый тест, и это мешает вам, приятно иметь возможность отключить его.
Tod
4
Без ошибок. Это не решение проблемы.
Tom W
3
Вы должны думать как инженер, а не как учёный !!
Эхсан Заргар Эршади 06
4
@Ehsan Ershadi, хороший инженер, предвидит и устраняет проблемы, а не прячет их под ковер!
Мо Патель,
4
СМЕШНО. Если вы не хотите видеть ошибку, вы можете просто поискать в другом месте, кроме монитора. То же самое и с вашим «решением». Это не выход. Это просто ИГНОРИРОВАНИЕ!
curiousBoy
0

Просто выберите «Исключения» из меню «Отладка» в окне Visual Studio 2005, появится всплывающее диалоговое окно «Edxception», выберите узел исключения «Управляемые помощники отладки», затем выберите ContextSwitchDeadlock и удалите выбор из столбца «Выброшенные». это остановит vs от выброса исключения ContextSwitchDeadlock.

Надеюсь это поможет..

Кумари Сони
источник
60
Ваша рука в огне. Просто используйте нож, чтобы перерезать нерв, который посылает боль в ваш мозг. Это не позволит вам заметить, что ваша рука горит.
Озза
В любом случае это способ временного решения проблемы. Чтобы полностью избавиться от этой проблемы, нужно время, чтобы пересмотреть дизайн приложения.
Ван Цзицзюнь
0

Я столкнулся с этой проблемой, когда пытался выяснить, почему я OracleDataReaderгенерировал исключение. Я думал, что это произошло из-за того, что оно было назначено, nullпотому что исключение было связано с параметром, имеющим значение null. Так я и сделал:

while (dr.Read())
{
    while (dr != null)  // <-- added this line
    {
      ...

Оказалось, что drэто НИКОГДА не было нулевым, и поэтому цикл просто продолжался и продолжался до тех пор, пока не пришло это сообщение, и снова и снова, потому что вы можете нажать «Продолжить», чтобы продолжить, пока у вас не закончится память (не делайте этого - вместо этого нажмите "ОК"). Итак, мораль истории: ищите утечки памяти, которые передают данные из базы данных в память в бесконечных циклах. Ошибка на самом деле пытается предупредить вас о плохом сценарии. Лучше прислушаться к этому.

vapcguy
источник
0

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

Я надеюсь, что это поможет кому-то.

Просто Руди
источник
0

Предполагая, что вы используете Visual Studio, вы можете щелкнуть Ctrl+Alt+Eтекущий проект, и отобразится окно исключений с выбором помощников по управляемой отладке, вы должны снять флажок с параметра «ContextSwitchDeadlock». затем создайте текущий проект.

Ашвини Триведи
источник