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


Режим конкурентности "Reentrant"

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

Определенный контракт представляет собой дуплексный контракт с Ping методом, реализуемым службой, и методом Pong обратного вызова, реализуемым клиентом. Клиент вызывает метод сервера Ping, используя счетчик тиков, тем самым инициируя вызов. Служба проверяет, не равен ли число галок 0, а затем вызывает метод обратного 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. Убедитесь, что вы выполнили процедуру настройки One-Time для образцов Windows Communication Foundation.

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

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

Демонстрирует

Чтобы запустить пример, создайте клиентские и серверные проекты. Затем откройте два окна команд и поменяйте каталоги на <образец>\CS\Service\bin\debug и <образец>\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