This property indicates whether an instance of a service can handle one thread or multiple threads that execute concurrently, and if single-threaded, whether reentrancy is supported.
Setting ConcurrencyMode to Single instructs the system to restrict instances of the service to one thread of execution at a time, which frees you from dealing with threading issues. A value of Multiple means that service objects can be executed by multiple threads at any one time. In this case, you must ensure thread safety.
Reentrantalso restricts access to a single thread at a time; while the operation is processing, no other message can enter the operation. If during the operation a call to another service leaves, the current message loses the lock on the operation, which is free to process other messages. When the service call out returns, the lock is reestablished and the original message can continue processing to its conclusion or until another call out of the operation occurs.
Note: |
|---|
It is your responsibility to leave your object state consistent before callouts and you must confirm that operation-local data is valid after callouts. Note that the service instance is unlocked only by calling another service over a WCF channel. In this case, the called service can reenter the first service via a callback. If the first service is not reentrant, the sequence of calls results in a deadlock. For details, see ConcurrencyMode. |
During any outbound call from a processing operation, data not local to the operation can be modified. (Local state data is guaranteed to be valid when the original message resumes processing.) As a result, before your outbound call you must ensure that non-local data is valid for other incoming calls and revalidate non-local data after the outbound call returns.
The following pseudo-code illustrates the required pattern for successful reentrant support.
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;
}
Using the Begin/End asynchronous call pattern for an outbound call when the ConcurrencyMode is Reentrant triggers an exception. Asynchronous outbound calls require an operation in which ConcurrencyMode is Multiple, in which case you must handle synchronization issues.
Generally, if a message arrives for an instance that violates its concurrency mode, the message waits until the instance is available, or until it times out.
In addition, if the ConcurrencyMode is set to Single and a reentrant call is blocked while waiting for the instance to be freed, the system detects the deadlock and throws an exception.
Note that you must explicitly set ReleaseServiceInstanceOnTransactionComplete to false if there is an operation with OperationBehaviorAttribute..::.TransactionScopeRequired set to true and you set ConcurrencyMode to Reentrant. Otherwise a validation exception is thrown because the default value of ReleaseServiceInstanceOnTransactionComplete is true.
There is an interaction of the ConcurrencyMode and other properties that can alter runtime behavior. For a complete description of these interactions, see Sessions, Instancing, and Concurrency.