Se detectó un error de ContextSwitchDeadlock en C #

80

Estoy ejecutando una aplicación C # y durante el tiempo de ejecución obtengo el siguiente error:

El CLR no ha podido realizar la transición del contexto COM 0x20e480 al contexto COM 0x20e5f0 durante 60 segundos. Es muy probable que el hilo que posee el contexto / apartamento de destino esté haciendo una espera sin bombeo o procesando una operación de ejecución muy larga sin bombear mensajes de Windows. Esta situación generalmente tiene un impacto negativo en el rendimiento e incluso puede hacer que la aplicación deje de responder o que el uso de la memoria se acumule continuamente con el tiempo. Para evitar este problema, todos los subprocesos de apartamento de un solo subproceso (STA) deben usar primitivas de espera de bombeo (como CoWaitForMultipleHandles) y mensajes de bombeo de forma rutinaria durante las operaciones de ejecución prolongada.

¿Alguien puede ayudarme con el problema aquí?

Muchas gracias.

asesino
fuente

Respuestas:

123

El hilo principal de su programa ha estado ocupado ejecutando código durante un minuto. No se está ocupando de sus tareas normales, bombeando el bucle de mensajes. Eso es ilegal cuando usa servidores COM en un hilo de trabajo: las llamadas a sus métodos no se pueden enviar hasta que su hilo principal vuelva a estar inactivo.

Debería ser fácilmente visible, su interfaz de usuario debería estar muerta como un clavo de puerta. Windows debería haber reemplazado su ventana principal con un fantasma que muestra "No responde". Cerrar la ventana no funcionará, ningún evento de clic tiene ningún efecto.

Lo que sea que esté haciendo su hilo principal debe hacerlo un hilo de trabajo en su lugar. La BackgroundWorkerclase es buena para eso, encontrará mucha ayuda de uso en el artículo de MSDN Library. Use Debug + Break All, Debug + Windows + Threads si no tiene idea de lo que está haciendo el hilo principal.

Una posible causa más: asegúrese de instalar el Service Pack 1 si está utilizando la versión RTM de VS2005.

Hans Passant
fuente
5
+1 por explicar que dicho elemento de trabajo debe moverse a un hilo secundario, por lo tanto, la solución sobre cómo evitar este error (en lugar de solo lo que produce el error).
JYelton
2
Es interesante que haya visto algunas otras aplicaciones creadas internamente que se cuelgan durante mucho más tiempo que la mía, pero recibí este mensaje de error, hmmm.
Coops
Documentación de MSDN: contextSwitchDeadlock MDA msdn.microsoft.com/en-us/library/ms172233%28v=vs.110%29.aspx
D_Bester
1
Gracias por la explicación detallada. Las soluciones alternativas que he usado son funciones asíncronas, que ahora tienen mucho sentido. Entonces, por lo que he recopilado, es muy importante administrar un nuevo hilo para operaciones de larga ejecución, especialmente cuando se utiliza COM.
Anthony Mason
50

Para encontrar qué operación bloquea el cambio de contexto y hace que se muestre el MDA contextSwitchDeadlock , puede utilizar los siguientes pasos. Tenga en cuenta que me referiré a Visual Studio 2012.

  1. Reproduzca el error. Esto podría implicar un poco de prueba y error.
  2. Haga clic en 'Aceptar' en lugar de 'Continuar' en el asistente de depuración administrada que se muestra.
  3. Asegúrese de que la barra de herramientas Ubicación de depuración esté activa haciendo clic con el botón derecho en la zona de acoplamiento de la barra de herramientas y seleccionando 'Ubicación de depuración'. Debería ver una lista desplegable con la etiqueta 'Subproceso' en la barra de herramientas si está activa.
  4. El elemento seleccionado en la lista desplegable del hilo debe ser un hilo diferente al hilo principal ya que será un hilo de fondo que se queja de que el hilo principal está acaparando toda la atención. Seleccione el hilo principal en la lista desplegable.
  5. Ahora debería ver el código que bloquea el cambio de contexto en el editor de código.

Suponiendo que decida no mover la operación que consume muchos recursos de su hilo principal, eche un vistazo a algunas de las otras respuestas y comentarios aquí antes de hacerlo, tiene las siguientes opciones para deshabilitar los asistentes de depuración administrados.

Dentro del depurador de Visual Studio

  1. Puede deshabilitar un MDA directamente en el cuadro de diálogo MDA que se muestra cuando se produce el error al desmarcar 'Interrumpir cuando se lanza este tipo de excepción'.
  2. Con el cuadro de diálogo Configuración de excepción siguiendo las instrucciones de MSDN a continuación .

... en el menú Depurar, haga clic en Excepciones. (Si el menú Depurar no contiene un comando Excepciones, haga clic en Personalizar en el menú Herramientas para agregarlo). En el cuadro de diálogo Excepciones, expanda la lista Asistentes de depuración administrados y, a continuación, desactive la casilla de verificación Lanzada para el MDA individual.

Fuera del depurador de Visual Studio

  1. Clave de registro (en todo el equipo, todos los MDA afectados)
  2. Variable de entorno (en toda la máquina, se pueden especificar MDA)
  3. Parámetros de configuración de la aplicación (ámbito de la aplicación, se pueden especificar MDA)

Nota: Una de las dos primeras opciones debe establecerse en 1 para que la tercera tenga algún efecto.

En mi caso, el problema fue una llamada a ObjectContext.SaveChanges () en Entity Framework dentro de una aplicación de consola. Con el MTAThreadAttribute aplicado al Main()método, la excepción ContextSwitchDeadlock ya no se generó . Lamentablemente, no estoy seguro de todos los efectos de este cambio.

Scott Munro
fuente
2
voto positivo por la explicación clara sobre cómo encontrar el código que bloquea el proceso.
Guillaume Schuermans
10

Este mensaje indica que algún código suyo está intentando cambiar de hilo y el hilo de destino está ocupado. Por ejemplo, un subproceso en segundo plano que intenta enviar una llamada al subproceso de la interfaz de usuario para actualizar la interfaz de usuario, mientras que la interfaz de usuario está ejecutando un ciclo cerrado durante un tiempo.

Para averiguar realmente qué está sucediendo, debe ingresar al depurador y observar todos los subprocesos y lo que están haciendo.

Franci Penov
fuente
4

En algunos casos:
Debug -> Exceptions -> Managed Debug Assistants
y desmarcando el elemento ContextSwitchDeadlock.

Ehsan Zargar Ershadi
fuente
5
Sí, pero cuando estás escribiendo una prueba única y esto se interpone en tu camino, es bueno poder desactivarla.
Tod
4
Sin error. Ésta no es una solución al problema.
Tom W
3
¡Tienes que pensar como un ingeniero, no como un científico!
Ehsan Zargar Ershadi
4
@Ehsan Ershadi, un buen ingeniero anticipa y soluciona problemas, ¡no lo esconde debajo de la alfombra!
Mo Patel
4
LOL. Si no quiere ver el error, simplemente puede buscar en otro lugar que no sea su monitor. Este es el mismo enfoque con su "solución". Esta no es una solución. ¡Esto es solo IGNORAR!
CuriousBoy
0

Simplemente seleccione Excepciones del menú Depurar en la ventana de Visual Studio 2005, aparecerá el cuadro de diálogo Edxception, seleccione el Nodo de excepción de los asistentes de depuración administrados, luego seleccione ContextSwitchDeadlock y elimine la selección de la columna Lanzado. esto evitará que vs lance la excepción ContextSwitchDeadlock.

Espero que esto ayude..

Kumari Sony
fuente
60
Tu brazo está en llamas. Simplemente use un cuchillo para cortar el nervio que envía dolor a su cerebro. Esto evitará que notes que tu brazo está en llamas.
Ozzah
De cualquier forma, esta es una forma de resolver el problema temporalmente. Para terminar con este problema, necesita algo de tiempo para reconsiderar el diseño de la aplicación.
Wang Jijun
0

Me encontré con este problema cuando estaba tratando de averiguar por qué OracleDataReaderestaba lanzando una excepción. Pensé que era porque se estaba asignando nullporque la excepción estaba relacionada con un parámetro que era `nulo. Así que lo hice:

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

Resultó que drNUNCA era nulo, por lo que el ciclo siguió y siguió hasta que llegó este mensaje, y siguió y siguió un poco más porque puede hacer clic en "Continuar" para que continúe hasta que se quede sin memoria (no haga esto - haga clic en "Aceptar" en su lugar). La moraleja de la historia es buscar fugas de memoria que estén transmitiendo datos desde la base de datos a la memoria en bucles hasta el infinito. En realidad, el error trata de advertirle de un mal escenario. Mejor prestarle atención.

vapcguy
fuente
0

Este error me apareció en numerosas ocasiones y lo rastreé hasta una iteración en DataGridViewRow , en la que establecí el valor de la casilla de verificación en verdadero. Como estaba ejecutando en modo de depuración, tenía la opción de continuar, así que pude hacer exactamente esto.

Espero que esto ayude a alguien.

Solo Rudy
fuente
0

Suponiendo que está usando Visual Studio, puede hacer clic Ctrl+Alt+Een el proyecto actual y se mostrará la ventana de excepciones con los asistentes de depuración administrados seleccionados, debe desmarcar la opción "ContextSwitchDeadlock". luego construya un proyecto actual.

AShwini Trivedi
fuente