ServiceBehaviorAttribute.ConcurrencyMode Eigenschaft
Definition
Wichtig
Einige Informationen beziehen sich auf Vorabversionen, die vor dem Release ggf. grundlegend überarbeitet werden. Microsoft übernimmt hinsichtlich der hier bereitgestellten Informationen keine Gewährleistungen, seien sie ausdrücklich oder konkludent.
Gibt an, ob ein Dienst einen Thread, mehrere Threads oder wiedereintrittsfähige Aufrufe unterstützt, oder legt dies fest.
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
Eigenschaftswert
Einer der ConcurrencyMode-Werte; der Standardwert ist Single.
Ausnahmen
Der Wert ist keiner der ConcurrencyMode-Werte.
Beispiele
Das folgende Codebeispiel veranschaulicht den Unterschied bei der Verwendung von Single, Reentrant und Multiple. Dieses Beispiel wird nicht ohne eine echte Implementierung kompiliert, sondern veranschaulicht die Art von Threadinggarantien, die Windows Communication Foundation (WCF) vornimmt, und was dies für Ihren Vorgangscode bedeutet.
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;
}
}
Hinweise
Diese Eigenschaft gibt an, ob eine Instanz eines Diensts einen Thread oder mehrere Threads, die gleichzeitig ausgeführt werden, verarbeiten kann; wenn der Dienst ein Singlethread ist, gibt sie an, ob Reentranz unterstützt wird.
Hinweis
Die ConcurrencyMode-Eigenschaft interagiert mit einigen anderen Einstellungen. Wenn der InstanceContextMode-Wert zum Beispiel auf Single festgelegt ist, kann der Dienst als Ergebnis nur jeweils eine Nachricht verarbeiten, es sei denn, Sie legen den ConcurrencyMode-Wert gleichzeitig auf Multiple fest. Diese Eigenschaft erzeugt ebenfalls Verhalten in Verbindung mit der ServiceContractAttribute.SessionMode-Eigenschaft. Ausführliche Informationen finden Sie unter Sitzungen, Instancing und Parallelität.
Das Festlegen von ConcurrencyMode auf Single weist das System an, Instanzen des Diensts auf jeweils einen ausgeführten Thread zu begrenzen, sodass Sie keine Threadingprobleme behandeln müssen. Der Wert Multiple bedeutet, das Dienstobjekte von mehreren Threads gleichzeitig ausgeführt werden können. In diesem Fall müssen Sie die Threadsicherheit sicherstellen.
Reentrant schränkt außerdem den Zugriff auf einen einzelnen Thread gleichzeitig ein. Während der Vorgang verarbeitet wird, kann keine andere Nachricht in den Vorgang eingegeben werden. Wenn während des Vorgangs ein Aufruf an einen anderen Dienst ausgegeben wird, verliert die aktuelle Nachricht die Sperre für den Vorgang, sodass dieser zum Verarbeiten anderer Nachrichten freigegeben ist. Wenn der ausgehende Dienstaufruf zurückkehrt, wird die Sperre wiederhergestellt, und die ursprüngliche Nachricht kann bis zum Abschluss oder bis ein weiterer Aufruf aus dem Vorgang auftritt weiter verarbeitet werden.
Wichtig
Auch wenn Single Instanzen des Diensts auf jeweils einen Ausführungsthread beschränkt werden, müssen Sie auch auf 1 festlegen MaxConcurrentCalls , um keine Nachrichten aus der Reihenfolge zu gewährleisten.
Darüber hinaus liegt es in Ihrer Verantwortung, den Objektzustand vor Legenden konsistent zu lassen, und Sie müssen bestätigen, dass lokale Vorgangsdaten nach Legenden gültig sind. Beachten Sie, dass die Dienstinstanz nur durch das Aufrufen eines anderen Diensts über einen WCF-Kanal entsperrt wird. In diesem Fall kann der aufgerufene Dienst über einen Rückruf wieder in den ersten Dienst eintreten. Wenn der erste Dienst nicht wiedereintrittsfähig ist, führt die Sequenz der Aufrufe zu einem Deadlock. Ausführliche Informationen finden Sie unter ConcurrencyMode.
Während ein ausgehender Aufruf von einem Verarbeitungsvorgang durchgeführt wird, können Daten, die nicht lokal zum Vorgang gehören, geändert werden. (Lokale Zustandsdaten sind garantiert gültig, wenn die ursprüngliche Nachricht mit der Verarbeitung fortgesetzt wird.) Daher müssen Sie vor dem ausgehenden Anruf sicherstellen, dass nicht lokale Daten für andere eingehende Anrufe gültig sind, und nicht lokale Daten nach der Rückgabe des ausgehenden Anrufs erneut aktualisieren.
Im folgenden Pseudocode wird das Muster, das für die erfolgreiche Unterstützung des Wiedereintritts notwendig ist, veranschaulicht.
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;
}
Durch die Verwendung des asynchronen Begin/End-Aufrufmusters für einen ausgehenden Aufruf, wenn ConcurrencyModeReentrant ist, wird eine Ausnahme ausgelöst. Asynchrone ausgehende Aufrufe benötigen einen Vorgang, in dem ConcurrencyModeMultiple ist; in diesem Fall müssen Sie Synchronisierungsprobleme beheben.
Im Allgemeinen wartet die Nachricht, bis die Instanz verfügbar ist oder bis ein Timeout auftritt, wenn eine Nachricht von einer Instanz eingeht, die gegen den Parallelitätsmodus verstößt.
Wenn ConcurrencyMode auf Single festgelegt ist und ein Reeentrant-Aufruf gesperrt wird, während darauf gewartet wird, dass die Instanz freigegeben wird, erkennt das System jedoch den Deadlock und löst eine Ausnahme aus.
Hinweis
Eine InvalidOperationException wird zur Laufzeit ausgelöst, falls ReleaseServiceInstanceOnTransactionCompletetrue
ist, wenn die ConcurrencyMode-Eigenschaft auf Single festgelegt ist.
Beachten Sie, dass Sie ReleaseServiceInstanceOnTransactionComplete explizit auf false
festlegen müssen, wenn ein Vorgang vorhanden ist, für den OperationBehaviorAttribute.TransactionScopeRequired auf "true" festgelegt ist, und Sie ConcurrencyMode auf Reentrant festlegen. Andernfalls wird eine Validierungsausnahme ausgelöst, da der Standardwert von ReleaseServiceInstanceOnTransactionCompletetrue
ist.
Es besteht einen Interaktion zwischen dem ConcurrencyMode und anderen Eigenschaften, die das Laufzeitverhalten ändern kann. Eine vollständige Beschreibung dieser Interaktionen finden Sie unter Sitzungen, Instancing und Parallelität.