다음을 통해 공유


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

ConcurrencyMode 값 중 하나입니다. 기본값은 Single입니다.

예외

값이 ConcurrencyMode 값 중 하나가 아닌 경우

예제

다음 코드 예제에서는 Single, ReentrantMultiple을 사용했을 때의 차이점을 보여 줍니다. 이 샘플을 뒤 실제 구현이 없어 컴파일되지 않습니다 하지만 보장 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 속성과 함께 동작을 생성합니다. 자세한 내용은 참조 하세요 세션, Instancing, and Concurrency합니다.

ConcurrencyModeSingle로 설정하면 시스템은 서비스의 인스턴스를 한 번에 하나의 실행 스레드로 제한하므로, 스레딩 문제를 처리하지 않아도 됩니다. 값이 Multiple이면 언제든지 한 번에 여러 스레드가 서비스 개체를 실행할 수 있습니다. 이런 경우 스레드 안전성을 확인해야 합니다.

Reentrant 또한에서는 한 번에 단일 스레드 액세스를 제한 작업을 처리 하는 동안 다른 메시지가 작업을 입력할 수 있습니다. 작업 중에 다른 서비스에 대한 호출이 발생하면 현재 메시지는 해당 작업에 대한 잠금을 해제하며 따라서 이 작업은 다른 메시지를 처리할 수 있습니다. 서비스 호출이 반환되면 잠금이 다시 설정되고 원래의 메시지가 처리 완료 시까지 또는 해당 작업에 대한 다른 호출이 발생할 때까지 처리를 계속할 수 있습니다.

중요

경우에 Single 인스턴스를 제한 한 번에 실행 한 스레드 서비스를 설정 해야 MaxConcurrentCalls 순서가 메시지가 없으면 보장 하려면 1로 합니다.

또한 개체 상태의 프로그램 호출 전에 일관성을 유지 해야 하 고 설명선이 포함 된 후에 작업-로컬 데이터가 유효한 지 확인 해야 합니다. 서비스 인스턴스는 WCF 채널을 통해 다른 서비스를 호출하는 방법으로만 잠금 해제됩니다. 이런 경우 호출된 서비스는 콜백을 통해 첫 번째 서비스에 재진입할 수 있습니다. 첫 번째 서비스가 재진입이 아닌 경우 호출 시퀀스는 교착 상태에 빠지게 됩니다. 자세한 내용은 ConcurrencyMode를 참조하십시오.

처리 중인 작업에서 아웃바운드 호출 도중, 해당 작업에 속하지 않은 데이터를 수정할 수 있습니다. 원래의 메시지가 다시 처리를 시작할 때 로컬 상태 데이터는 항상 유효합니다. 따라서 아웃바운드 호출에 앞서 먼저, 작업에 속하지 않은 데이터가 다른 들어오는 호출에 대해 유효한지 확인하고, 아웃바운드 호출 반환 후에는 작업에 속하지 않은 데이터의 유효성을 다시 검사해야 합니다.

다음 의사(pseudo) 코드에서는 성공적인 재진입 지원에 필요한 패턴을 보여 줍니다.

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

ConcurrencyModeReentrant일 때 아웃바운드 호출에 대해 Begin/End 비동기 호출 패턴을 사용하면 예외가 트리거됩니다. 비동기 아웃바운드 호출에서는 ConcurrencyModeMultiple인 작업이 필요하며, 이 경우 사용자는 동기화 문제를 처리해야 합니다.

일반적으로 인스턴스에 대해 동시성 모드를 위반하는 메시지가 도착할 경우 그 메시지는 인스턴스가 사용 가능해지거나 시간 제한이 초과할 때까지 대기합니다.

또한 ConcurrencyModeSingle로 설정되었으며 인스턴스가 해제될 때까지 기다리는 동안 재진입 호출이 차단되는 경우, 시스템은 교착 상태를 감지하고 예외를 throw합니다.

참고

InvalidOperationException 속성이 ReleaseServiceInstanceOnTransactionComplete로 설정된 상태에서 trueConcurrencyMode인 경우에는 런타임에 Single이 throw됩니다.

ReleaseServiceInstanceOnTransactionComplete이 true로 설정된 작업이 있고 falseOperationBehaviorAttribute.TransactionScopeRequired로 설정한 경우, 명시적으로 ConcurrencyModeReentrant로 설정해야 합니다. 그렇지 않으면, ReleaseServiceInstanceOnTransactionComplete의 기본값이 true이므로 유효성 검사 예외가 throw됩니다.

ConcurrencyMode와 다른 속성 간의 상호 작용이 있어서 런타임 동작을 바꿀 수 있습니다. 이러한 상호 작용의 설명은 참조 하세요 세션, Instancing, and Concurrency합니다.

적용 대상