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 和其他属性之间的交互可能会更改运行时行为。 有关这些交互的完整说明,请参阅 会话、实例化和并发

适用于