Pergunta

Tenho um serviço WCF auto-hospedado e estou tendo o seguinte problema:15 minutos após a criação da instância do serviço, as chamadas TryEnter na operação dos métodos de contrato retornam constantemente falso, mas as chamadas TryEnter na função Main, que também utiliza sincronização via classe Monitor, retornam verdadeiro.

Aqui está a descrição do meu aplicativo e do bug:Estou desenvolvendo um serviço WCF auto-hospedado no Visual Studio 2008 (C#) no Windows XP SP2.A instância ServiceHost do host é criada no início da função Main.A função Main executa um loop while (true) durante o qual realiza leituras, escritas, manutenção periódicas, etc.Existe uma coleção estática de objetos (que podem ser adicionados ou removidos ao longo do tempo), que atuam como contêineres para threads de trabalho.Alguns desses threads realizam trabalhos periódicos solicitados pela função Main, enquanto outros realizam leitura e gravação sob demanda em um dispositivo remoto.O bloqueio da sincronização é feito nesses objetos usando a classe Monitor (métodos TryEnter e Exit).Esses objetos também são acessados ​​através dos métodos de contrato de serviço (serviços) utilizando as mesmas funções.A sincronização é feita entre a função Main e os métodos de serviço.Quando a instância do serviço é criada, ela é executada com desempenho projetado por exatamente 15 minutos, após os quais cada chamada TryEnter(obj, timeout) feita no serviço retorna false após o tempo limite especificado expirar.No entanto, isso não afeta as chamadas TryEnter feitas na função Main, ou seja,eles sempre retornam verdadeiros.Tentei alterar as configurações para InstanceContextMode, ConcurrencyMode, juntamente com atributos de limitação de serviço maxConcurrentCalls="1";maxConcurrentSessions="5" e todas as configurações produziram o mesmo efeito.O serviço responde novamente quando eu reinicio o aplicativo host, mas não quando fecho e reabro à força o host enquanto o aplicativo está em execução (a instância do serviço permanece na memória).Não se trata de indisponibilidade do serviço, pois a chamada nunca chega à instância de serviço.O método é chamado, sua execução chega à chamada TryEnter que precede a seção crítica do método e TryEnter apenas retorna false após o tempo limite (15 segundos).Eu verifiquei e verifiquei novamente os pares de TryEnter e Exit – os métodos sempre liberam o bloqueio quando a seção crítica termina.Outras operações contratuais que não utilizam bloqueio ou os objetos em questão funcionam bem mesmo após o término do período de 15 minutos.

Obrigado a todos antecipadamente.Boas férias!

Foi útil?

Solução

Monitor é reentrante, então parece que o tópico com o seu Main método não conseguiu liberar um bloqueio.Então, quando ele pede o bloqueio (TryEnter) ele obtém o bloqueio (incrementando o contador em outro um).

Todos os outros tópicos serão negados.Você precisará depurar onde o bloqueio é obtido e mantido.

Eu verifiquei e verifiquei novamente os pares de TryEnter e Exit – os métodos sempre liberam o bloqueio quando a seção crítica termina

desculpe, mas acho que você vai verificar três vezes.Em particular, ao contrário lock, TryEnter não terá nenhum tratamento de exceção especial.Seu código deve ficar assim:

if(Monitor.TryEnter(lockObj, timeout)) {
    try {
        ...
    } finally {
        Monitor.Exit(lockObj);
    }
}

Além disso - certifique-se de nunca reatribuir seu lockObj no código, pois isso não desbloqueará o objeto correto.

(ou similar usando um sinalizador, especialmente no .NET 4.0 onde há novas sobrecargas para Enter etc)

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