ServiceBehaviorAttribute.ConcurrencyMode プロパティ

定義

サービスが、1 つのスレッド、複数のスレッド、または再入呼び出しをサポートするかどうかを示す値を取得または設定します。

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 値の 1 つ。既定値は Single です。

例外

値が、ConcurrencyMode 値ではありません。

次のコード例は、SingleReentrant、および Multiple の各使用方法の相違を示します。 このサンプルは、実際の実装なしでコンパイルされるわけではありませんが、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;
  }
}

注釈

このプロパティは、サービスのインスタンスが 1 つのスレッドまたは同時に実行する複数のスレッドを処理できるかどうか、またシングル スレッドの場合は再入をサポートしているかどうかを示します。

Note

ConcurrencyMode プロパティは、他のいくつかの設定と相互関係があります。 たとえば、InstanceContextMode 値を Single に設定した場合は、ConcurrencyMode 値を Multiple に設定しない限り、サービスが一度に処理できるのは 1 つのメッセージだけです。 このプロパティと ServiceContractAttribute.SessionMode プロパティを組み合わせて、特定の動作を設定することもできます。 詳細については、「 セッション、インスタンス化、コンカレンシー」を参照してください。

ConcurrencyModeSingle に設定すると、サービスのインスタンスを 1 つずつのスレッド実行に制限するようシステムに指示します。それにより、スレッドの問題に対応することから解放されます。 Multiple の値は、サービス オブジェクトを複数のスレッドで一度に実行できることを示します。 この場合は、開発者がスレッド セーフを確保する必要があります。

Reentrant では、一度に 1 つのスレッドへのアクセスも制限されます。操作の処理中は、他のメッセージが操作に入る可能性はありません。 操作の進行中に、別のサービスに対する呼び出しがコール アウトした場合は、操作に対する現在のメッセージのロックは失われ、他のメッセージの処理が可能になります。 サービスのコール アウトが戻ると、ロックが再度確立され、元のメッセージを最後まで処理するか、別のコール アウトが発生するまで処理を続行できます。

重要

サービスのインスタンスを一度に 1 つの実行スレッドに制限する Single 場合でも、順序が誤ったメッセージがないことを保証するには、1 に設定 MaxConcurrentCalls する必要もあります。

また、吹き出しの前にオブジェクトの状態を一貫性を保ち、引き出し後に操作ローカル データが有効であることを確認する必要があります。 サービス インスタンスは、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 である操作を必要とします。この場合は、開発者が同期問題を処理する必要があります。

通常、コンカレンシー モードに違反するインスタンスにメッセージが届いた場合は、そのインスタンスが使用可能になるまで、またはタイムアウトになるまで、メッセージは待機します。

さらに、ConcurrencyModeSingle に設定され、再入可能呼び出しが、インスタンスが解放されるまで待機する間ブロックされた場合、システムはデッドロックを検出し、例外をスローします。

Note

InvalidOperationException プロパティに ReleaseServiceInstanceOnTransactionComplete が設定されているときに、trueConcurrencyMode の場合は、実行時に Single がスローされます。

ReleaseServiceInstanceOnTransactionComplete が true に設定された操作があるときに falseOperationBehaviorAttribute.TransactionScopeRequired に設定する場合は、ConcurrencyModeReentrant に明示的に設定する必要があることに注意してください。 ReleaseServiceInstanceOnTransactionComplete の既定値は true であるため、この設定を行わなかった場合は検証例外がスローされます。

ConcurrencyMode と他のプロパティの間には、ランタイム動作を変更する可能性がある相互関係があります。 これらの相互作用の詳細については、「 セッション、インスタンス化、コンカレンシー」を参照してください。

適用対象