Wykryto błąd ContextSwitchDeadlock w C #


80

Uruchamiam aplikację C # i podczas wykonywania otrzymuję następujący błąd:

Środowisko CLR nie mogło przejść z kontekstu COM 0x20e480 do kontekstu COM 0x20e5f0 przez 60 sekund. Wątek będący właścicielem kontekstu / apartamentu docelowego najprawdopodobniej albo wykonuje oczekiwanie bez pompowania, albo przetwarza bardzo długotrwałą operację bez pompowania komunikatów systemu Windows. Ta sytuacja ma ogólnie negatywny wpływ na wydajność i może nawet prowadzić do braku odpowiedzi aplikacji lub ciągłego zwiększania się zużycia pamięci. Aby uniknąć tego problemu, wszystkie wątki z pojedynczym wątkiem (STA) powinny używać elementów podstawowych oczekiwania pompowania (takich jak CoWaitForMultipleHandles) i rutynowo pompować komunikaty podczas długotrwałych operacji.

Czy ktoś może mi pomóc w rozwiązaniu problemu?

Wielkie dzięki.

Odpowiedzi:


123

Główny wątek twojego programu był zajęty wykonywaniem kodu przez minutę. Nie zajmuje się swoimi normalnymi obowiązkami, pompując pętlę komunikatów. Jest to nielegalne, gdy używasz serwerów COM w wątku roboczym: wywołania ich metod nie mogą być wysyłane, dopóki główny wątek nie przejdzie ponownie w stan bezczynności.

Powinien być dobrze widoczny, a interfejs użytkownika powinien być martwy jak gwóźdź do drzwi. System Windows powinien zastąpić okno główne widmem z komunikatem „Brak odpowiedzi”. Zamknięcie okna nie zadziała, żadne zdarzenia kliknięcia nie mają żadnego efektu.

Cokolwiek robi twój główny wątek, powinno być zamiast tego zrobione przez wątek roboczy. Ta BackgroundWorkerklasa jest do tego dobra, znajdziesz wiele pomocy dotyczących użytkowania w artykule MSDN Library. Użyj Debug + Break All, Debug + Windows + Threads, jeśli nie masz pojęcia, co robi główny wątek.

Jeszcze jedna możliwa przyczyna: pamiętaj, aby zainstalować dodatek Service Pack 1, jeśli używasz wersji RTM VS2005.


5
+1 za wyjaśnienie, że taki element pracy powinien zostać przeniesiony do drugiego wątku, a zatem rozwiązanie, jak uniknąć tego błędu (a nie tylko, co powoduje błąd).
JYelton

2
Ciekawe, że widziałem, jak kilka innych wbudowanych aplikacji zawiesza się znacznie dłużej niż moja, ale trafiłem na ten komunikat o błędzie, hmmm.
Coops

Dokumentacja MSDN: contextSwitchDeadlock MDA msdn.microsoft.com/en-us/library/ms172233%28v=vs.110%29.aspx
D_Bester

1
Dzięki za szczegółowe wyjaśnienie. Obejścia, których użyłem, to funkcje asynchroniczne, które teraz mają sens. Z tego, co wiem, bardzo ważne jest, aby zarządzać nowym wątkiem w przypadku długotrwałych operacji, szczególnie w przypadku korzystania z COM.
Anthony Mason

50

Aby dowiedzieć się, która operacja blokuje przełącznik kontekstu i powoduje wyświetlenie MDA contextSwitchDeadlock , możesz wykonać następujące czynności. Zwróć uwagę, że będę odnosić się do Visual Studio 2012.

  1. Odtwórz błąd. Może to wymagać prób i błędów.
  2. Kliknij „OK” zamiast „Kontynuuj” w wyświetlonym asystencie zarządzanego debugowania.
  3. Upewnij się, że pasek narzędzi Lokalizacja debugowania jest aktywny, klikając prawym przyciskiem myszy region dokowania paska narzędzi i wybierając opcję „Lokalizacja debugowania”. Jeśli jest aktywna, na pasku narzędzi powinna pojawić się lista rozwijana z etykietą „Wątek”.
  4. Wybrany element z listy rozwijanej Wątek powinien być wątkiem innym niż wątek główny, ponieważ będzie to wątek w tle, który narzeka, że ​​główny wątek skupia całą uwagę. Wybierz główny wątek z rozwijanej listy.
  5. Powinieneś teraz zobaczyć kod, który blokuje przełączanie kontekstu w edytorze kodu.

Zakładając, że zdecydujesz się nie przenosić operacji wymagającej dużej ilości zasobów z głównego wątku - zanim to zrobisz, zapoznaj się z niektórymi innymi odpowiedziami i komentarzami - masz następujące opcje wyłączania asystentów zarządzanego debugowania.

W programie Visual Studio Debugger

  1. Możesz wyłączyć MDA bezpośrednio w oknie dialogowym MDA, które jest wyświetlane, gdy wystąpi błąd, odznaczając opcję „Przerwij po wyrzuceniu tego typu wyjątku”.
  2. Z oknem dialogowym Ustawienia wyjątków, korzystając z poniższych instrukcji z witryny MSDN .

... w menu Debug kliknij opcję Wyjątki. (Jeśli menu Debugowanie nie zawiera polecenia Wyjątki, w menu Narzędzia kliknij opcję Dostosuj, aby je dodać). W oknie dialogowym Wyjątki rozwiń listę Asystentów zarządzanego debugowania, a następnie wyczyść pole wyboru Zgłoszone dla poszczególnych MDA.

Poza debugerem programu Visual Studio

  1. Klucz rejestru (dla całego komputera, dotyczy wszystkich MDA)
  2. Zmienna środowiskowa (dla całego komputera, można określić MDA)
  3. Ustawienia konfiguracji aplikacji (można określić zakres aplikacji, umowy MDA)

Uwaga: Jedna z pierwszych dwóch opcji musi być ustawiona na 1, aby trzecia miała jakikolwiek efekt.

W moim przypadku problemem było wywołanie ObjectContext.SaveChanges () w Entity Framework w aplikacji konsoli. Po zastosowaniu MTAThreadAttribute do Main()metody wyjątek ContextSwitchDeadlock nie był już zgłaszany . Niestety, nie jestem pewien, jakie będą skutki tej zmiany.


2
Głosuj za jasnym wyjaśnieniem dotyczącym znalezienia kodu blokującego proces.
Guillaume Schuermans

10

Ten komunikat wskazuje, że jakiś Twój kod próbuje przełączyć wątki, a wątek docelowy jest zajęty. Na przykład wątek w tle, który próbuje wysłać wywołanie do wątku interfejsu użytkownika, aby zaktualizować interfejs użytkownika, podczas gdy interfejs użytkownika przez pewien czas wykonuje ciasną pętlę.

Aby dowiedzieć się, co się dzieje, musisz włamać się do debugera i przyjrzeć się wszystkim wątkom i tym, co robią.


4

W niektórych przypadkach:
Debug -> Wyjątki -> Managed Debug Assistants
i odznaczenie elementu ContextSwitchDeadlock.


5
Tak, ale kiedy piszesz jednorazowy test i to przeszkadza, dobrze jest móc go wyłączyć.
Tod

4
Nie, źle. To nie jest rozwiązanie problemu.
Tom W

3
Musisz myśleć jak inżynier, a nie naukowiec !!
Ehsan Zargar Ershadi

4
@Ehsan Ershadi, dobry inżynier przewiduje i rozwiązuje problemy, a nie wpycha go pod dywan!
Mo Patel,

4
LOL. Jeśli nie chcesz widzieć błędu, możesz po prostu spojrzeć gdzie indziej niż monitor. To jest to samo podejście do twojego „rozwiązania”. To nie jest rozwiązanie. To po prostu IGNOROWANIE!
ciekawyBoy

0

Po prostu wybierz Wyjątki z menu Debug w oknie programu Visual Studio 2005, pojawi się okno dialogowe Edxception, wybierz węzeł wyjątku Managed Debugging Assistants, a następnie wybierz ContextSwitchDeadlock i usuń zaznaczenie z kolumny Thrown. spowoduje to, że vs nie zgłosi wyjątku ContextSwitchDeadlock.

Mam nadzieję że to pomoże..


60
Twoje ramię płonie. Po prostu użyj noża, aby przeciąć nerw, który powoduje ból w mózgu. Dzięki temu nie zauważysz, że twoja ręka płonie.
Ozzah

W każdym razie jest to sposób tymczasowego rozwiązania problemu. Aby całkowicie odciąć się od tego problemu, potrzeba trochę czasu na ponowne przemyślenie projektu aplikacji.
Wang Jijun

0

Napotkałem ten problem, próbując dowiedzieć się, dlaczego OracleDataReaderrzucam wyjątek. Myślałem, że dzieje się tak, ponieważ został przypisany, nullponieważ wyjątek był powiązany z parametrem o wartości `null. Więc zrobiłem:

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

Okazało się, że drNIGDY nie było null, więc pętla po prostu trwała i trwała, dopóki nie nadeszła ta wiadomość, i dalej i dalej, ponieważ możesz kliknąć „Kontynuuj”, aby kontynuować, dopóki nie zabraknie pamięci (nie rób tego - kliknij „OK”). Więc morał tej historii, szukaj wycieków pamięci, które przesyłają dane z bazy danych do pamięci w pętli do nieskończoności. Błąd faktycznie próbuje ostrzec Cię przed złym scenariuszem. Najlepiej to zważać.


0

Ten błąd pojawiał się u mnie wiele razy i wyśledziłem go do iteracji w DataGridViewRow, w której ustawiłem wartość pola wyboru na true. Ponieważ pracowałem w trybie debugowania, miałem możliwość kontynuowania, więc mogłem to zrobić.

Mam nadzieję, że to komuś pomoże.


0

Zakładając, że używasz programu Visual Studio, możesz kliknąć Ctrl+Alt+Ew bieżącym projekcie, a okno wyjątków zostanie wyświetlone z wybranymi asystentami zarządzanego debugowania, należy odznaczyć opcję „ContextSwitchDeadlock”. następnie zbuduj bieżący projekt.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.