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 值。

範例

下列程式碼範例將示範使用 SingleReentrantMultiple 之間的差異。 此範例不會在沒有實際實作後方進行編譯,但會示範 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 屬性一起使用的行為。 如需詳細資訊,請參閱 會話、實例和並行

ConcurrencyMode 設定為 Single,便會指示系統要將服務的執行個體限制為一次執行一個執行緒,這樣您就不需要處理執行緒問題。 值為 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;
}

ConcurrencyModeReentrant 時,對傳出呼叫使用 Begin/End 非同步呼叫模式會觸發例外狀況。 非同步傳出呼叫需要 ConcurrencyModeMultiple 的作業,而在該情況下,您必須處理同步處理問題。

一般來說,如果違反其並行模式的執行個體有訊息到達,該訊息會等到執行個體可供使用為止,或等到它逾時為止。

此外,如果 ConcurrencyMode 設定為 Single,且可重新進入的呼叫在等待釋放執行個體時遭到封鎖,系統就會偵測到此死結並擲回例外狀況。

注意

InvalidOperationException 屬性設定為 ReleaseServiceInstanceOnTransactionComplete 時,如果 trueConcurrencyMode,便會在執行階段擲回 Single

請注意,如果有作業的 ReleaseServiceInstanceOnTransactionComplete 設定為 true,且您將 false 設定為 OperationBehaviorAttribute.TransactionScopeRequired,則您必須將 ConcurrencyMode 明確設定為 Reentrant。 否則,便會擲回驗證例外狀況,因為 ReleaseServiceInstanceOnTransactionComplete 的預設值為 true

ConcurrencyMode 和其他屬性之間的互動可以改變執行階段行為。 如需這些互動的完整描述,請參閱 會話、實例和並行

適用於