Synchronization Contexts
This is about ‘Declarative Locking’. Rather than locking manually, one can lock declaratively.
By deriving from ContextBoundObject and applying the Synchronization attribute, one instructs the CLR to apply locking automatically. Here's an example:
Simple Example –
| using System.Threading; using System.Runtime.Remoting.Contexts; [Synchronization] public class AutoLock : ContextBoundObject { public void Demo() { Console.Write("Start..."); Thread.Sleep(1000); // We can't be preempted here Console.WriteLine("end"); // thanks to automatic locking! } } public class Test { public static void { AutoLock safeInstance = new AutoLock(); new Thread(safeInstance.Demo).Start(); // Call the Demo new Thread(safeInstance.Demo).Start(); // method 3 times safeInstance.Demo(); // concurrently. } } Output – Start... end Start... end Start... end |
The CLR ensures that only one thread can execute code in safeInstance at a time.
It does this by creating a single synchronizing object – and Locking It Around Every Call to each of safeInstance's methods or properties.
The scope of the lock – in this case – the safeInstance object – is called a Synchronization Context.
Furthermore, we haven't solved a problem described earlier (Refer Post - Threading || Thread-Safety and .NET Framework Types) : if AutoLock were a collection class, we'd still require a lock around such below statements, assuming it ran from another class: unless this code's class was itself a synchronized ContextBoundObject!
| if (safeInstance.Count > 0) { safeInstance.RemoveAt (0); } |
A synchronization context can extend beyond the scope of a single object. By default, if a synchronized object is instantiated from within the code of another, both share the same context (in other words, one big lock!) This behavior can be changed by specifying an integer flag in Synchronization attribute's constructor, using one of the constants defined in the SynchronizationAttribute class:
Constant | Meaning |
NOT_SUPPORTED | Equivalent to not using the Synchronized attribute |
SUPPORTED | Joins the existing synchronization context if instantiated from another synchronized object, otherwise remains unsynchronized |
REQUIRED (default) | Joins the existing synchronization context if instantiated from another synchronized object, otherwise creates a new context |
REQUIRES_NEW | Always creates a new synchronization context |
Reentrancy
A thread-safe method is sometimes called Reentrant, because it can be preempted part way through its execution, and then called again on another thread Without Ill Effect.
In a general sense, the terms thread-safe and reentrant are considered either synonymous or closely related.
Reentrancy, however, has another more sinister connotation in automatic locking regimes. If the Synchronization attribute is applied with the reentrant argument true:
[Synchronization(true)]
then the synchronization context's lock will be temporarily released when execution leaves the context. A side effect is that during this interim, any thread is free to call any method on the original object ("re-entering" the synchronization context) and unleashing the very complications of multithreading one is trying to avoid in the first place. This is the problem of reentrancy.
Hope this helps.
Thanks & Regards,
Arun Manglick || Senior Tech Lead
No comments:
Post a Comment