Partilhar via


ServiceBehaviorAttribute.ConcurrencyMode Propriedade

Definição

Obtém ou define se um serviço dá suporte a um thread, vários threads ou chamadas reentrantes.

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

Valor da propriedade

ConcurrencyMode

Um dos valores ConcurrencyMode; o padrão é Single.

Exceções

O valor não é um dos valores ConcurrencyMode.

Exemplos

O exemplo de código a seguir demonstra a diferença entre usar Singlee ReentrantMultiple. Este exemplo não é compilado sem uma implementação real por trás dele, mas demonstra o tipo de garantias de threading que Windows WCF (Communication Foundation) faz e o que isso significa para o código de operação.

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

Comentários

Essa propriedade indica se uma instância de um serviço pode lidar com um thread ou vários threads que são executados simultaneamente e se há suporte para uma única thread.

Observação

A ConcurrencyMode propriedade interage com algumas outras configurações. Por exemplo, se o InstanceContextMode valor for definido como Single resultado, o serviço só poderá processar uma mensagem por vez, a menos que você também defina o ConcurrencyMode valor como Multiple. Essa propriedade também produz comportamento em combinação com a ServiceContractAttribute.SessionMode propriedade. Para obter detalhes, consulte Sessões, Instancing e Simultaneidade.

A configuração ConcurrencyMode para Single instrui o sistema a restringir instâncias do serviço a um thread de execução por vez, o que libera você de lidar com problemas de threading. Um valor de meios que os objetos de Multiple serviço podem ser executados por vários threads a qualquer momento. Nesse caso, você deve garantir a segurança do thread.

Reentrant também restringe o acesso a um único thread por vez; enquanto a operação está sendo processada, nenhuma outra mensagem pode entrar na operação. Se durante a operação uma chamada para outro serviço sair, a mensagem atual perderá o bloqueio na operação, que é livre para processar outras mensagens. Quando a chamada de serviço retorna, o bloqueio é restabelecido e a mensagem original pode continuar processando até sua conclusão ou até que outra chamada fora da operação ocorra.

Importante

Embora restrinja Single instâncias do serviço a um thread de execução por vez, você também deve definir MaxConcurrentCalls como 1 para garantir nenhuma mensagem fora de ordem.

Além disso, é sua responsabilidade deixar o estado do objeto consistente antes dos textos explicativos e você deve confirmar que os dados locais de operação são válidos após os textos explicativos. Observe que a instância do serviço é desbloqueada somente chamando outro serviço em um canal do WCF. Nesse caso, o serviço chamado pode reinserir o primeiro serviço por meio de um retorno de chamada. Se o primeiro serviço não for reentrante, a sequência de chamadas resultará em um deadlock. Para obter detalhes, consulte ConcurrencyMode.

Durante qualquer chamada de saída de uma operação de processamento, os dados não locais para a operação podem ser modificados. (Os dados de estado local têm a garantia de serem válidos quando a mensagem original retomar o processamento.) Como resultado, antes da chamada de saída, você deve garantir que os dados não locais sejam válidos para outras chamadas de entrada e revalidar dados não locais após o retorno da chamada de saída.

O pseudocódigo a seguir ilustra o padrão necessário para o suporte de reentrant bem-sucedido.

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

Usando o padrão de chamada assíncrona Begin/End para uma chamada de saída quando o ConcurrencyMode is Reentrant dispara uma exceção. Chamadas de saída assíncronas exigem uma operação na qual ConcurrencyMode , Multiplenesse caso, você deve lidar com problemas de sincronização.

Em geral, se uma mensagem chegar para uma instância que viole seu modo de simultaneidade, a mensagem aguardará até que a instância esteja disponível ou até atingir o tempo limite.

Além disso, se a ConcurrencyMode chamada for definida Single e uma chamada reentrante for bloqueada enquanto aguarda a liberação da instância, o sistema detectará o deadlock e gerará uma exceção.

Observação

A InvalidOperationException é lançada no runtime se ReleaseServiceInstanceOnTransactionComplete for true quando a ConcurrencyMode propriedade está definida como Single.

Observe que você deve definir ReleaseServiceInstanceOnTransactionComplete false explicitamente se há uma operação com definido como OperationBehaviorAttribute.TransactionScopeRequired true e definido ConcurrencyMode como Reentrant. Caso contrário, uma exceção de validação será gerada porque o valor ReleaseServiceInstanceOnTransactionComplete padrão é true.

Há uma interação entre as propriedades e outras que podem alterar o ConcurrencyMode comportamento do runtime. Para obter uma descrição completa dessas interações, consulte Sessões, Instancamento e Simultaneidade.

Aplica-se a