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
Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.
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.
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