Поделиться через


Повторный вход ConcurrencyMode

В примере Reentrant демонстрируется необходимость и последствия использования concurrencyMode.Reentrant в реализации службы. Поведение ConcurrencyMode.Reentrant подразумевает, что служба (или обратный вызов) обрабатывает только одно сообщение в данный момент времени (аналогично ConcurencyMode.Single). Чтобы обеспечить безопасность потоков, Windows Communication Foundation (WCF) блокирует обработку InstanceContext сообщения, чтобы другие сообщения не могли обрабатываться. В режиме Reentrant объект InstanceContext разблокируется непосредственно перед тем, как служба делает исходящий вызов, что делает возможным последующий вызов (который может быть реентерабельным, как показано в этом образце), и снова блокируется при следующем его поступлении в службу. Для демонстрации этого поведения в образце показано, как клиент и служба могут отправлять сообщения друг другу, используя дуплексный контракт.

Определенный в примере контракт является дуплексным: метод Ping реализуется службой, а метод обратного вызова Pong реализуется клиентом. Клиент вызывает метод Ping сервера со счетчиком тактов, тем самым инициируя вызов. Служба проверяет, отличен ли счетчик тактов от нуля, и затем вызывает метод обратного вызова Pong, одновременно уменьшая на единицу счетчик тактов. Это делает следующий код в образце.

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

Реализация метода Pong обратного вызова имеет ту же логику, что и реализация метода Ping. Это значит, что она сравнивает значение счетчика тактов с нулем, а затем вызывает метод Ping по каналу обратного вызова (в данном случае это канал, который использовался для отправки исходного сообщения Ping), уменьшая счетчик тактов на 1. Когда счетчик тактов достигает 0, метод завершает работу, возвращая все ответы в первый вызов, выполненный клиентом, который запустил вызов. Это показано в реализации обратного вызова.

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

И метод Ping, и метод Pong работают по шаблону "запрос-ответ", что означает, что первый вызов метода Ping не возвращается, пока не будет возвращен вызов метода CallbackChannel<T>.Pong(). На стороне клиента метод Pong не может возвратиться до тех пор, пока не будет возвращен следующий сделанный им вызов метода Ping. Поскольку и обратный вызов, и служба должны делать исходящие вызовы "запрос-ответ", прежде чем они смогут ответить на ожидающий запрос, обе реализации должны быть отмечены поведением ConcurrencyMode.Reentrant.

Настройка, сборка и выполнение образца

  1. Убедитесь, что вы выполнили процедуру однократной установки для примеров Windows Communication Foundation.

  2. Чтобы создать выпуск решения на языке C# или Visual Basic .NET, следуйте инструкциям в разделе Building the Windows Communication Foundation Samples.

  3. Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в разделе "Примеры Windows Communication Foundation".

Что демонстрирует

Чтобы выполнить образец, постройте клиентский и серверный проекты. Затем откройте два окна команд и измените каталоги на <образец>\CS\Service\bin\debug и <sample>\CS\Client\bin\debug каталоги. Затем запустите службу, введя service.exe , а затем вызовите Client.exe с начальным значением тиков, переданных в качестве входного аргумента. Ниже показаны результаты выполнения для количества тактов, равного 10.

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