ServiceBehaviorAttribute.ConcurrencyMode Propriété

Définition

Obtient ou définit si un service prend en charge un thread, plusieurs threads ou des appels réentrants.

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

Valeur de propriété

Une des valeurs ConcurrencyMode ; la valeur par défaut est Single.

Exceptions

La valeur ne fait pas partie des valeurs ConcurrencyMode.

Exemples

L'exemple de code suivant illustre la différence entre l'utilisation de Single, Reentrant et Multiple. Cet exemple ne se compile pas sans une implémentation réelle derrière lui, mais il illustre le type de garanties de threading que Windows Communication Foundation (WCF) offre et ce que cela signifie pour votre code d’opération.

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

Remarques

Cette propriété indique si une instance d'un service peut gérer un ou plusieurs threads exécutés simultanément et si, en cas d'utilisation monothread, la réentrance est prise en charge.

Notes

La propriété ConcurrencyMode interagit avec plusieurs autres paramètres. Par exemple, si InstanceContextMode a la valeur Single, votre service ne peut traiter qu'un message à la fois, excepté si vous affectez la valeur ConcurrencyMode à Multiple. Cette propriété produit également un comportement en association avec la propriété ServiceContractAttribute.SessionMode. Pour plus d’informations, consultez Sessions, instanciation et concurrence.

Le fait d'affecter à ConcurrencyMode la valeur Single permet de demander au système de restreindre les instances du service à un thread d'exécution à la fois, ce qui vous évite d'avoir à gérer des problèmes de thread. La valeur Multiple signifie que plusieurs threads à la fois peuvent exécuter les objets de service. Dans ce cas, vous devez garantir la sécurité des threads.

Reentrant restreint également l’accès à un seul thread à la fois ; pendant le traitement de l’opération, aucun autre message ne peut entrer l’opération. Si, pendant l'opération, un appel à un autre service est envoyé, le message actuel désactive le verrouillage de l'opération, qui est alors libre de traiter d'autres messages. Lorsque l'appel de service revient, le verrouillage est rétabli et le message d'origine peut continuer à traiter jusqu'à son terme ou jusqu'à ce qu'un autre appel soit lancé par l'opération.

Important

Bien que Single limite les instances du service à un seul thread d’exécution à la fois, vous devez également définir MaxConcurrentCalls sur 1 pour garantir l’absence de messages dans l’ordre.

En outre, il est de votre responsabilité de laisser votre état d’objet cohérent avant les légendes et vous devez vérifier que les données locales d’opération sont valides après les légendes. Notez que l’instance de service est déverrouillée uniquement en appelant un autre service sur un canal WCF. Dans ce cas, le service appelé peut réentrer le premier service via un rappel. Si le premier service n'est pas réentrant, la séquence des appels provoque un interblocage. Pour plus d'informations, consultez ConcurrencyMode.

Lors de tout appel sortant à partir d'une opération de traitement, il est possible de modifier les données non locales de l'opération. (La validité des données d’état local est garantie lorsque le message d’origine reprend le traitement.) Par conséquent, avant votre appel sortant, vous devez vous assurer que les données non locales sont valides pour d’autres appels entrants et revalider les données non locales après le retour de l’appel sortant.

Le pseudo-code suivant illustre le modèle requis pour la prise en charge des appels réentrants.

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

L'utilisation du modèle d'appel asynchrone Begin/End pour un appel sortant lorsque le ConcurrencyMode a la valeur Reentrant déclenche une exception. Les appels sortants asynchrones requièrent une opération dans laquelle le ConcurrencyMode a la valeur Multiple, auquel cas vous devez gérer les problèmes de synchronisation.

En règle générale, si un message est reçu pour une instance qui enfreint son mode d'accès concurrentiel, le message patiente jusqu'à ce que l'instance soit disponible ou expire.

Qui plus est, si ConcurrencyMode a la valeur Single et qu'un appel réentrant est bloqué jusqu'à ce que l'instance soit libérée, le système détecte l'interblocage et lève une exception.

Notes

Une InvalidOperationException est levée au moment de l'exécution si ReleaseServiceInstanceOnTransactionComplete a la valeur true lorsque la propriété ConcurrencyMode a la valeur Single.

Notez que vous devez affecter explicitement la valeur ReleaseServiceInstanceOnTransactionComplete à false s'il existe une opération avec OperationBehaviorAttribute.TransactionScopeRequired dont la valeur est true et que vous affectez la valeur ConcurrencyMode à Reentrant. Sinon, une exception de validation est levée car la valeur par défaut de ReleaseServiceInstanceOnTransactionComplete est true.

Il existe une interaction des ConcurrencyMode et d'autres propriétés qui peut altérer le comportement au moment de l'exécution. Pour obtenir une description complète de ces interactions, consultez Sessions, instanciation et concurrence.

S’applique à