Compartir a través de


ConcurrencyMode Enumeración

Definición

Especifica si una clase de servicio admite modos de operación de subproceso único o múltiple.

public enum class ConcurrencyMode
public enum ConcurrencyMode
type ConcurrencyMode = 
Public Enum ConcurrencyMode
Herencia
ConcurrencyMode

Campos

Multiple 2

La instancia del servicio es de subproceso múltiple. No se realiza ninguna garantía de sincronización. Dado que otros subprocesos pueden cambiar en cualquier momento su objeto de servicio, debe administrar en todo momento la coherencia del estado y la sincronización.

Reentrant 1

La instancia del servicio es de subproceso único y acepta llamadas reentrantes. El servicio reentrante acepta llamadas al llamar a otro servicio; es, por consiguiente, responsabilidad suya el establecer un estado de objeto coherente antes de las llamadas y debe confirmar que los datos locales de operaciones sean válidos después de las llamadas. Tenga en cuenta que la instancia del servicio solo se desbloquea llamando a otro servicio a través de un canal de WCF. En este caso, el servicio al que se ha llamado puede reentrar al primer servicio mediante una devolución de llamada. Si el primer servicio no es reentrante, la secuencia de llamadas resulta en un interbloqueo. Para obtener información detallada, vea ConcurrencyMode.

Single 0

La instancia del servicio es de subproceso único y no acepta llamadas reentrantes. Si la propiedad InstanceContextMode es Single, y los mensajes adicionales llegan mientras la instancia repara una llamada, estos mensajes deben esperar hasta que el servicio esté disponible o hasta que los mensajes superen el tiempo de espera.

Ejemplos

En el ejemplo de código siguiente se muestra la diferencia entre usar Single, Reentrant y Multiple. Este ejemplo no se compila sin una implementación real detrás de él, pero demuestra el tipo de garantías de subproceso que WCF realiza y lo que significa para el código de operación.

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

Comentarios

ConcurrencyMode se utiliza junto con la propiedad ConcurrencyMode para especificar si una clase de servicio admite de modos de operación de subproceso único o múltiple. Una operación de subproceso único puede ser reentrante o no reentrante.

En la tabla siguiente se muestra cuándo Windows Communication Foundation (WCF) permite invocar una operación mientras hay otra en curso, dependiendo de ConcurrencyMode.

Valor de ConcurrencyMode ¿Se puede invocar una nueva operación?
Single Nunca.
Reentrante Sólo al invocar otro servicio o una devolución de llamada.
Múltiple Siempre.

Se aplica a