Pergunta

Eu escrevi um componente COM em .NET e se eu tentar tirar um bloqueio em qualquer objeto em qualquer método (que é chamado pelo código não gerenciado falando com a minha componente COM) eu recebo uma exceção.

Eu não tenho o texto exato da exceção, neste momento, mas não foi muito útil também.

Então, minha pergunta é em que circunstâncias um bloqueio (SyncObject) iria lançar uma exceção? Aqui estão alguns fatos:

  • SyncObject não é nulo
  • SyncObject não estiver bloqueado

Será que tem alguma coisa a ver com callee executado em STA (Single Threaded Apartment) ou MTA (Multi-Threaded Apartment)?

Foi útil?

Solução

A partir desta página :

Cada aquisição de bloqueio pode lançar uma exceção. Estar preparado para isso.

A maioria das fechaduras preguiçosamente alocar um evento se a aquisição de bloqueio encontra disputa, incluindo monitores CLR. Essa alocação pode falhar durante a condições de recursos insuficientes, causando Ooms proveniente da entrada para o bloqueio. (Note-se que um típico sem bloqueio bloqueio de rotação não pode falhar com OOM, que permite que ele seja usado em alguns cenários com recursos limitados como dentro de um CER.) Da mesma forma, uma série como o SQL Server pode executar a detecção de impasse e até mesmo quebrar os impasses por gerar exceções que se originam a partir da declaração Enter, manifestando-se como um System.Runtime.InteropServices.COMException.

Muitas vezes não há muito que pode ser feito em resposta a essa excepção. Mas o código reliability- e sensíveis à segurança que deve lidar com o fracasso robusta deve considerar este caso. Teríamos gostado que fosse o caso de que os impasses de acolhimento pode ser respondido de forma inteligente, mas a maioria código da biblioteca não pode inteligentemente descontrair a um ponto seguro na pilha para que ele possa voltar-off e repita a operação. Há simplesmente muito cross-biblioteca misturando em uma pilha típico. É por isso que à base de tempo limite aquisições monitor com TryEnter são tipicamente uma má idéia para a prevenção de impasse.

Então, como você pode ler, parece que sob condições de recursos limitados poderíamos obter exceções lançadas a partir do método Enter do Monitor que bloqueio (o) usa internamente.

Por isso, talvez a sua solução é algo como um spin-espera?

{
    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);
        }
    }
}

Onde cond poderia ser algum

private volatile int cond = 0

usadas com, por exemplo Interlocked.CompareExchange onde muda para o exemplo Thread.Current.ManagedThreadID ou diferente de zero outra coisa?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top