Domanda

Ho scritto un componente com in .NET e se provo a bloccare un oggetto su qualsiasi metodo (che viene invocato da codice non gestito che parla al mio componente com) ottengo un'eccezione.

Al momento non ho il testo esatto dell'eccezione, ma non è stato neanche molto utile.

Quindi la mia domanda è in quali circostanze un lock (syncObject) genererebbe un'eccezione? Ecco alcuni fatti:

  • syncObject non è null
  • syncObject non è già bloccato

Avrebbe qualcosa a che fare con la chiamata in esecuzione in STA (Single Threaded Apartment) o MTA (Multi Threaded Apartment)?

È stato utile?

Soluzione

Da questa pagina :

  

Ogni acquisizione di blocco potrebbe generare un'eccezione. Preparati per questo.

     

La maggior parte dei blocchi alloca pigramente un evento se un'acquisizione di blocco incontra contese, inclusi i monitor CLR. Questa allocazione può non riuscire in condizioni di risorse limitate, causando OOM provenienti dall'ingresso al blocco. (Si noti che un tipico spin lock non bloccante non può fallire con OOM, il che consente di utilizzarlo in alcuni scenari con risorse limitate come all'interno di un CER.) Allo stesso modo, un host come SQL Server può eseguire il rilevamento di deadlock e persino rompere tali deadlock con generare eccezioni che provengono dall'istruzione Enter, manifestandosi come System.Runtime.InteropServices.COMException.

     

Spesso non c'è molto da fare in risposta a tale eccezione. Ma il codice sensibile all'affidabilità e alla sicurezza che deve affrontare in modo efficace i guasti dovrebbe considerare questo caso. Ci sarebbe piaciuto che fosse possibile rispondere in modo intelligente ai deadlock dell'host, ma la maggior parte del codice della libreria non può svolgersi in modo intelligente in un punto sicuro dello stack in modo da poter eseguire il back-off e riprovare l'operazione. C'è semplicemente troppa mescolanza tra librerie su uno stack tipico. Questo è il motivo per cui le acquisizioni di Monitor basate sul timeout con TryEnter sono generalmente una cattiva idea per la prevenzione dei deadlock.

Come puoi leggere, sembra che in condizioni di risorse limitate potremmo ricevere eccezioni dal metodo Enter di Monitor che lock (o) utilizza internamente.

Quindi forse la tua soluzione è qualcosa come uno 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);
        }
    }
}

Dove cond potrebbe essere un po '

private volatile int cond = 0

utilizzato con ad es. Interlocked.CompareExchange dove si passa ad es. Thread.Current.ManagedThreadID o qualcos'altro diverso da zero?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top