Labels

Monday, June 15, 2009

Threading ||Synchronization Contexts || Reentrancy

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 Main()

        {

            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