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


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 значение, то служба может обрабатывать только одно сообщение одновременно, если значение не задано ConcurrencyModeMultiple. Это свойство также создает поведение в сочетании со свойством ServiceContractAttribute.SessionMode . Дополнительные сведения см. в разделе "Сеансы", "Instancing" и "Параллелизм".

Установка инструкций ConcurrencyModeSingle системе ограничить экземпляры службы одним потоком выполнения за раз, что освобождает вас от решения проблем с потоком. Значение 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 для исходящего вызова при ConcurrencyModeReentrant срабатывании исключения. Асинхронные исходящие вызовы требуют операции, в которой ConcurrencyMode есть Multiple, в этом случае необходимо обрабатывать проблемы синхронизации.

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

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

Замечание

Создается InvalidOperationException во время выполнения, если ConcurrencyModeReleaseServiceInstanceOnTransactionCompletetrue задано Singleзначение свойства.

Обратите внимание, что необходимо явно задать ReleaseServiceInstanceOnTransactionComplete значение, если имеется операция с OperationBehaviorAttribute.TransactionScopeRequired значением true, и задано значение ConcurrencyModeReentrant.false В противном случае возникает исключение проверки, так как значение ReleaseServiceInstanceOnTransactionComplete по умолчанию равно true.

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

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