Compartilhar via


ConcurrencyMode Reentrant

O exemplo reentrante demonstra a necessidade e as implicações do uso de ConcurrencyMode.Reentrant em uma implementação de serviço. ConcurrencyMode.Reentrant implica que o serviço (ou retorno de chamada) processa apenas uma mensagem em um determinado momento (análogo a ConcurencyMode.Single). Para garantir a segurança do thread, o WCF (Windows Communication Foundation) bloqueia o processamento de uma mensagem por InstanceContext para que nenhuma outra mensagem possa ser processada. No caso do modo Reentrante, o InstanceContext é desbloqueado pouco antes de o serviço fazer uma chamada de saída, permitindo que a chamada subsequente (que pode ser reentrante conforme demonstrado no exemplo) obtenha o bloqueio na próxima vez que ele chegar ao serviço. Para demonstrar o comportamento, o exemplo mostra como um cliente e um serviço podem enviar mensagens entre si usando um contrato duplex.

O contrato definido é duplex com o método Ping sendo implementado pelo serviço e o método Pong de retorno de chamada sendo implementado pelo cliente. Um cliente invoca o método Ping do servidor com uma contagem em escala iniciando a chamada. O serviço verifica se a contagem em escala não é igual a 0 e, em seguida, invoca o método Pong de retorno de chamada ao decrementar a contagem em escala. Isso é feito pelo código a seguir no exemplo.

public void Ping(int ticks)
{
     Console.WriteLine("Ping: Ticks = " + ticks);
     //Keep pinging back and forth till Ticks reaches 0.
     if (ticks != 0)
     {
         OperationContext.Current.GetCallbackChannel<IPingPongCallback>().Pong((ticks - 1));
     }
}

A implementação de Pong do retorno de chamada tem a mesma lógica que a implementação Ping. Ou seja, verifica se a contagem de tiques não é zero e, em seguida, invoca o método Ping no canal de retorno de chamada (nesse caso, é o canal que foi usado para enviar a mensagem Ping original) com a contagem em escala decrementada por 1. No momento em que a contagem em escala atinge 0, o método retorna desembrulhando todas as respostas de volta para a primeira chamada feita pelo cliente que iniciou a chamada. Isso é mostrado na implementação de retorno de chamada.

public void Pong(int ticks)
{
    Console.WriteLine("Pong: Ticks = " + ticks);
    if (ticks != 0)
    {
        //Retrieve the Callback  Channel (in this case the Channel which was used to send the
        //original message) and make an outgoing call until ticks reaches 0.
        IPingPong channel = OperationContext.Current.GetCallbackChannel<IPingPong>();
        channel.Ping((ticks - 1));
    }
}

Os métodos Ping e Pong são solicitação/resposta, que significa que a primeira chamada para Ping não retorna até que a chamada a CallbackChannel<T>.Pong() retorna. No cliente, o método Pong não pode retornar até a próxima chamada Ping que ele fez retornar. Como o retorno de chamada e o serviço precisam fazer chamadas de solicitação/resposta de saída antes de responder a solicitação pendente, ambas as implementações precisam ser marcadas com o comportamento ConcurrencyMode.Reentrant.

Para configurar, compilar, e executar o exemplo

  1. Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.

  3. Para executar o exemplo em uma configuração de computador único ou cruzado, siga as instruções em Como executar os exemplos do Windows Communication Foundation.

Demonstra

Para executar o exemplo, crie os projetos de cliente e servidor. Em seguida, abra duas janelas de comando e altere os diretórios para os <diretórios sample>\CS\Service\bin\debug e <sample>\CS\Client\bin\debug. Em seguida, inicie o serviço digitando service.exe e, depois, invoque o Client.exe com o valor inicial dos tiques passados como um argumento de entrada. Uma saída de exemplo para 10 tiques é mostrada.

Prompt>Service.exe
ServiceHost Started. Press Enter to terminate service.
Ping: Ticks = 10
Ping: Ticks = 8
Ping: Ticks = 6
Ping: Ticks = 4
Ping: Ticks = 2
Ping: Ticks = 0

Prompt>Client.exe 10
Pong: Ticks = 9
Pong: Ticks = 7
Pong: Ticks = 5
Pong: Ticks = 3
Pong: Ticks = 1