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


ServiceBehaviorAttribute.ConcurrencyMode Свойство

Определение

Возвращает или задает поддержку службой одного потока, нескольких потоков или повторных входящих вызовов.

public:
 property System::ServiceModel::ConcurrencyMode ConcurrencyMode { System::ServiceModel::ConcurrencyMode get(); void set(System::ServiceModel::ConcurrencyMode value); };
public System.ServiceModel.ConcurrencyMode ConcurrencyMode { get; set; }
member this.ConcurrencyMode : System.ServiceModel.ConcurrencyMode with get, set
Public Property ConcurrencyMode As ConcurrencyMode

Значение свойства

Одно из значений ConcurrencyMode; значение по умолчанию — Single.

Исключения

Данное значение не является одним из значений ConcurrencyMode.

Примеры

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

using System;
using System.ServiceModel;

[ServiceContract]
public interface IHttpFetcher
{
  [OperationContract]
  string GetWebPage(string address);
}

// These classes have the invariant that:
//     this.slow.GetWebPage(this.cachedAddress) == this.cachedWebPage.
// When you read cached values you can assume they are valid. When
// you write the cached values, you must guarantee that they are valid.
// With ConcurrencyMode.Single, WCF does not call again into the object
// so long as the method is running. After the operation returns the object
// can be called again, so you must make sure state is consistent before
// returning.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
class SingleCachingHttpFetcher : IHttpFetcher
{
    string cachedWebPage;
    string cachedAddress;
    readonly IHttpFetcher slow;

    public string GetWebPage(string address)
    {
        // <-- Can assume cache is valid.
        if (this.cachedAddress == address)
        {
            return this.cachedWebPage;
        }

        // <-- Cache is no longer valid because we are changing
        // one of the values.
        this.cachedAddress = address;
        string webPage = slow.GetWebPage(address);
        this.cachedWebPage = webPage;
        // <-- Cache is valid again here.

        return this.cachedWebPage;
        // <-- Must guarantee that the cache is valid because we are returning.
    }
}

// With ConcurrencyMode.Reentrant, WCF makes sure that only one
// thread runs in your code at a time. However, when you call out on a
// channel, the operation can get called again on another thread. Therefore
// you must confirm that state is consistent both before channel calls and
// before you return.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
class ReentrantCachingHttpFetcher : IHttpFetcher
{
  string cachedWebPage;
  string cachedAddress;
  readonly SlowHttpFetcher slow;

  public ReentrantCachingHttpFetcher()
  {
    this.slow = new SlowHttpFetcher();
  }

  public string GetWebPage(string address)
  {
    // <-- Can assume that cache is valid.
    if (this.cachedAddress == address)
    {
        return this.cachedWebPage;
    }

    // <-- Must guarantee that the cache is valid, because
    // the operation can be called again before we return.
    string webPage = slow.GetWebPage(address);
    // <-- Can assume cache is valid.

    // <-- Cache is no longer valid because we are changing
    // one of the values.
    this.cachedAddress = address;
    this.cachedWebPage = webPage;
    // <-- Cache is valid again here.

    return this.cachedWebPage;
    // <-- Must guarantee that cache is valid because we are returning.
  }
}

// With ConcurrencyMode.Multiple, threads can call an operation at any time.
// It is your responsibility to guard your state with locks. If
// you always guarantee you leave state consistent when you leave
// the lock, you can assume it is valid when you enter the lock.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
class MultipleCachingHttpFetcher : IHttpFetcher
{
  string cachedWebPage;
  string cachedAddress;
  readonly SlowHttpFetcher slow;
  readonly object ThisLock = new object();

  public MultipleCachingHttpFetcher()
  {
    this.slow = new SlowHttpFetcher();
  }

  public string GetWebPage(string address)
  {
    lock (this.ThisLock)
    {
      // <-- Can assume cache is valid.
      if (this.cachedAddress == address)
      {
          return this.cachedWebPage;
          // <-- Must guarantee that cache is valid because
          // the operation returns and releases the lock.
      }
      // <-- Must guarantee that cache is valid here because
      // the operation releases the lock.
    }

    string webPage = slow.GetWebPage(address);

    lock (this.ThisLock)
    {
      // <-- Can assume cache is valid.

      // <-- Cache is no longer valid because the operation
      // changes one of the values.
      this.cachedAddress = address;
      this.cachedWebPage = webPage;
      // <-- Cache is valid again here.

      // <-- Must guarantee that cache is valid because
      // the operation releases the lock.
    }

    return webPage;
  }
}

Комментарии

Это свойство указывает, может ли экземпляр службы обрабатывать один поток или несколько потоков, выполняемых одновременно, и поддерживаются ли повторные входящие вызовы в однопоточном режиме.

Примечание

Свойство ConcurrencyMode взаимодействует с некоторыми другими параметрами. Например, если значение InstanceContextMode задано как Single, служба сможет обрабатывать в конкретный момент времени только одно сообщение, пока значение ConcurrencyMode также не будет задано как Multiple. Это свойство также задает поведение в сочетании со свойством ServiceContractAttribute.SessionMode. Дополнительные сведения см. в разделах Сеансы, инстансирование и параллелизм.

Установка для параметра ConcurrencyMode значения Single приводит к тому, что система не дает экземплярам службы одновременно выполнять более одного потока, что позволяет избежать решения вопросов многопоточности. Значение Multiple означает, что объекты службы могут выполняться несколькими потоками одновременно. В этом случае необходимо обеспечить безопасность потоков.

Reentrant также ограничивает доступ к одному потоку за раз; пока операция обрабатывается, другое сообщение не может войти в операцию. Если во время операции вызов другой службы исчезает, текущее сообщение теряет блокировку операции, которая может обрабатывать другие сообщения. Когда вызов службы возвращается, блокировка восстанавливается и исходное сообщение продолжает обрабатываться до завершения или до возникновения другого вызова операции.

Важно!

Несмотря на то, что Single экземпляры службы ограничиваются одним потоком выполнения за раз, необходимо также задать значение MaxConcurrentCalls 1, чтобы гарантировать отсутствие неупорядоченных сообщений.

Кроме того, вы несете ответственность за то, чтобы состояние объекта было согласовано перед выносками, и вы должны убедиться, что локальные данные операции действительны после выносок. Обратите внимание, что экземпляр службы разблокируется только путем вызова другой службы по каналу WCF. В этом случае вызванная служба может повторно войти в первую службу через обратный вызов. Если первая служба не допускает повторные входящие вызовы, последовательность вызовов приводит к взаимоблокировке. Дополнительные сведения см. в разделе ConcurrencyMode.

Во время любого исходящего вызова из обрабатывающей операции нелокальные в отношении операции данные могут быть изменены. (Данные локального состояния гарантированно будут действительными при возобновлении обработки исходного сообщения.) В результате перед исходящим вызовом необходимо убедиться, что данные, не являющиеся локальными, допустимы для других входящих вызовов, и повторно проверить данные, не являющиеся локальными, после возврата исходящего вызова.

В следующем псевдокоде показан необходимый шаблон для успешной поддержки повторных входящих вызовов.

public void MyMethod()
{
  this.SomeNonLocalDataState;
  // Here you need to clean nonlocal state for other users
  OutboundProxy proxy = new OutboundProxy();
  int returnValue = proxy.CallOutOfOperation();
  // Ensure that this.SomeNonLocalDataState is valid for continued use.
  this.ModifyNonLocalState;
  return returnValue;
}

С помощью шаблона асинхронных вызовов Begin/End для исходящего вызова, когда ConcurrencyMode является Reentrant, выдается исключение. Для асинхронных исходящих вызовов требуется операция, при которой ConcurrencyMode является Multiple, и в этом случае следует обработать проблемы синхронизации.

Обычно в случае прибытия сообщения для экземпляра, нарушающего режим параллелизма, сообщение ожидает доступности экземпляра или истечения срока своего действия.

Кроме того, если для параметра ConcurrencyMode задано значение Single и если повторный входящий вызов блокируется во время ожидания освобождения экземпляра, система обнаруживает взаимоблокировку и выдает исключение.

Примечание

Во время выполнения выдается InvalidOperationException, если ReleaseServiceInstanceOnTransactionComplete является true, когда свойство ConcurrencyMode задано как Single.

Обратите внимание, что необходимо явно задать ReleaseServiceInstanceOnTransactionCompletefalse, если имеется операция с OperationBehaviorAttribute.TransactionScopeRequired, заданным как true, и задается ConcurrencyMode как Reentrant. В противном случае будет выдано исключение проверки, поскольку значение по умолчанию ReleaseServiceInstanceOnTransactionCompletetrue.

Существует взаимодействие ConcurrencyMode и других свойств, которые могут изменить поведение среды выполнения. Полное описание этих взаимодействий см. в разделе Сеансы, инстансирование и параллелизм.

Применяется к