Pregunta

He escrito un componente com en .NET y si trato de bloquear un objeto en cualquier método (que es invocado por código no administrado que habla con mi componente com) obtengo una excepción.

No tengo el texto exacto de la excepción en este momento, pero tampoco fue de mucha ayuda.

Entonces, mi pregunta es ¿bajo qué circunstancias un bloqueo (syncObject) arrojaría una excepción? Aquí hay algunos hechos:

  • syncObject no es nulo
  • syncObject aún no está bloqueado

¿Tendría algo que ver con la persona que realiza la llamada en STA (apartamento de subproceso único) o MTA (apartamento de subprocesos múltiples)?

¿Fue útil?

Solución

De esta página :

  

Cada adquisición de bloqueo puede generar una excepción. Prepárate para ello.

     

La mayoría de los bloqueos asignan perezosamente un evento si una adquisición de bloqueo encuentra contención, incluidos los monitores CLR. Esta asignación puede fallar durante condiciones de bajos recursos, causando OOM que se originan desde la entrada a la cerradura. (Tenga en cuenta que un bloqueo de giro típico sin bloqueo no puede fallar con OOM, lo que permite que se use en algunos escenarios con recursos limitados, como dentro de un CER). De manera similar, un host como SQL Server puede realizar la detección de puntos muertos e incluso romper esos puntos muertos por generando excepciones que se originan en la instrucción Enter, que se manifiesta como System.Runtime.InteropServices.COMException.

     

A menudo no se puede hacer mucho en respuesta a dicha excepción. Pero el código sensible a la confiabilidad y la seguridad que debe lidiar con las fallas de manera sólida debería considerar este caso. Nos hubiera gustado que los bloqueos de host se puedan responder de forma inteligente, pero la mayoría del código de la biblioteca no puede desenrollarse de forma inteligente a un punto seguro en la pila para que pueda retroceder y volver a intentar la operación. Simplemente hay demasiada mezcla entre bibliotecas en una pila típica. Esta es la razón por la cual las adquisiciones de Monitor basadas en tiempo de espera con TryEnter suelen ser una mala idea para la prevención de puntos muertos.

Entonces, como puede leer, parece que bajo condiciones de recursos limitados podríamos obtener excepciones del método Enter de Monitor que Lock (o) usa internamente.

Entonces, ¿tal vez su solución es algo así como un spin-wait?

{
    uint iters = 0;
    while (!cond) {
        if ((++iters % 50) == 0) {
            // Every so often we sleep with a 1ms timeout (see #30 for justification).
            Thread.Sleep(1);
        } else if (Environment.ProcessorCount == 1) {
            // On a single-CPU machine we yield the thread.
            Thread.Sleep(0);
        } else {
            // Issue YIELD instructions to let the other hardware thread move.
            Thread.SpinWait(25);
        }
    }
}

¿Dónde podría haber alguna?

private volatile int cond = 0

utilizado con p. Interlocked.CompareExchange donde cambia, p. Thread.Current.ManagedThreadID o algo más distinto de cero?

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