Pregunta

Larga historia corta: en una aplicación C# que funciona con Com InProc-Server (DLL), me encuentro con "0x80010100: Call System Falling" Exception, y en el modo de depuración también contextwitchdeadlock.

Ahora más en detalles:

1) La aplicación C# inicializa STA, crea un objeto COM (registrado como "apartamento"); Luego, se suscribe a su punto de conexión, y comienza a trabajar con el objeto.

2) En alguna etapa, el objeto COM genera muchos eventos, pasando como argumento una gran colección de objetos COM, que se crean en el mismo apartamento.

3) El manejo de eventos en el lado de C# procesa la colección anterior, y ocasionalmente llama a algunos métodos de los objetos. En algún momento, las últimas llamadas comienzan a fallar con las excepciones anteriores.

En el lado com, el apartamento usa una ventana oculta cuyo winproc se ve así:

typedef std::function<void(void)> Functor;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)   
{   
  switch(msg)   
  {   
    case AM_FUNCTOR:
    {
      Functor *f = reinterpret_cast<Functor *>(lParam);
      (*f)();
      delete f;
    }
    break;   
    case WM_CLOSE:   
      DestroyWindow(hwnd);   
    break;   
    default:   
      return DefWindowProc(hwnd, msg, wParam, lParam);   
  }   
  return 0;   
} 

Los eventos se publican en esta ventana desde otras partes del servidor COM:

void post(const Functor &func)
{
  Functor *f = new Functor(func);
  PostMessage(hWind_, AM_FUNCTOR, 0, reinterpret_cast<LPARAM>(f));
}

Los eventos son implementaciones estándar de ATL CP vinculadas con los parámetros reales, y se reducen a algo como esto:

pConnection->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);

En C# el manejador se ve así:

private void onEvent(IMyCollection objs)
{
  int len = objs.Count; // usually 10000 - 25000
  foreach (IMyObj obj in objs)
  {
    // some of the following calls fail with 0x80010100
    int id = obj.id;
    string name = obj.name;
    // etc...
  }
}

==================

Entonces, ¿puede ocurrir el problema anterior solo porque la cola de mensaje del apartamento está demasiado cargada con los eventos que intenta entregar? ¿O el bucle del mensaje debe estar totalmente bloqueado para causar tal comportamiento?

Supongamos que el mensaje de mensaje tiene 2 eventos secuenciales que evalúan a la llamada "OneVent". El primero ingresa al código administrado de C#, que intenta volver a ingresar el código no administrado, el mismo apartamento. Por lo general, esto está permitido, y lo hacemos mucho. ¿Cuándo, en qué circunstancias puede fallar?

Gracias.

¿Fue útil?

Solución

Esto debería funcionar incluso con múltiples apartamentos siempre que:

  • Solo uno de los hilos responde a eventos externos como tráfico de red, temporizadores, mensajes publicados, etc.
  • Otros hilos solo solicitudes de servicio Com (incluso si vuelven a llamar al hilo principal durante el procesamiento).

Y

  • Ninguna cola de hilos se llena, evitando que Com se comunique con el hilo.

En primer lugar:Parece que algunos objetos no están en el mismo apartamento que otros objetos. ¿Estás seguro de que todos los objetos se están creando en el STA?

Lo que está describiendo es un punto muerto clásico: dos hilos independientes, cada uno esperando el otro. Eso es lo que esperaría que ocurra con ese diseño que funciona con los lados C# y com en diferentes hilos.

Deberías estar bien si todos Los objetos están en el mismo hilo, así como la ventana oculta que está en ese hilo, por lo que creo que debe verificar eso. (Obviamente, esto incluye cualquier otro objeto creado por el lado COM y que se pase al lado de C#).

Puede intentar depurar esto presionando "Pausa" en el depurador y verificando qué código estaba en cada hilo (si ve rpcrt*.dll Esto significa que está viendo un proxy). Alternativamente, podría imprimir la ID de hilo actual de varios puntos críticos en los lados C# y Com y su WNDProc, todos deberían ser lo mismo.

En segundo lugar: Debe funcionar con múltiples hilos siempre que solo uno de los hilos genera elementos de trabajo, y el otro no hace más que objetos com al host que responden a las llamadas (es decir, no genera llamadas de temporizadores, tráfico de red, mensajes publicados), en Este caso puede ser que la cola de hilo esté llena y COM no pueda responder a una llamada.

En lugar de usar la cola de hilo, debe usar un deque protegido por una sección crítica.

Puede mantener un contador de elementos encendido/apagado de la cola para ver si este es el problema.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top