Context

for RuBoard

In order for us to understand how the runtime is able to enforce a threading requirement based on an attribute, we have to introduce the concept of context. Step 4 of the Threading example is the same code as Step 3, but with some additional output:

 Is the customer object a proxy? False  Is the bookings object a proxy? True  Added Boston Presidential Hotel with one room.  Thread 13 ContextId 0 launching 3 threads.  MakeReservation: Thread 28 ContextId 0 starting.  Reserving for Customer 1 at the Boston Presidential Hotel                        on 12/12/2001 12:00:00 AM for 3 days  Thread 28 ContextId 1 entered Reserve.  MakeReservation: Thread 29 ContextId 0 starting.  Reserving for Customer 2 at the Boston Presidential Hotel                        on 12/13/2001 12:00:00 AM for 1 days  CancelReservation: Thread 30 ContextId 0 starting.  Cancelling Reservation 10  Thread 28 ContextId 1 left Reserve.  Thread 29 ContextId 1 entered Reserve.  Thread 29 ContextId 1 left Reserve.  Reservation for Customer 2 could not be booked  Room not available  Thread 30 ContextId 1 entered CancelReservation.  Thread 30 ContextId 1 left CancelReservation.  Reservation for Customer 1 has been booked  ReservationId = 1  ReservationRate = 10000  ReservationCost = 30000  Comment = OK 

In the last step of the Threading example we see that when a thread enters a method of the Broker class, it has a different ContextId than when it runs outside of the Broker class. It runs in a different context.

 MakeReservation: Thread 28 ContextId 0 starting.  ...      Thread 28 ContextId 1 entered Reserve. 

Objects derived from Broker have different runtime requirements (such as different synchronization requirements) than the other objects in the program, since access to Broker objects must be synchronized and access to other objects need not be synchronized. The environment that represents an object's runtime requirements that the CLR needs to be aware of is called a context . There are two contexts in the Threading Step 3 example ”Context 1 where the Broker object lives and Context 0 where all other objects live. Every thread in the program runs in Context 1 when executing inside a Broker object, Context 0 everywhere else. Contexts are independent of threads.

A context is a collection of one or more objects that have identical runtime requirements. The .NET concept of a context is identical to the COM+ concept of a context. [10] In general you cannot say what the runtime must do to in a given context because it depends on exactly what the runtime requirements are. A context that has transactional requirements requires different action than one that does not. Or a context that has to maintain a REQUIRED synchronization requirement is different from one that has to maintain a REQUIRES_NEW synchronization requirement.

[10] At this point in time, though, COM+ contexts and .NET contexts are different. For a discussion of contexts in COM+ see Understanding and Programming COM+ by Robert J. Oberg.

You can get the Context class instance that represents the current context from the static property Thread.CurrentContext . ContextId is a property of that class.

Proxies and Stubs

How does the runtime enforce the different requirements of different contexts? When an object resides in another context (such as the HotelBroker object in the NewReservation instance), an object reference to a proxy object is returned instead of a reference to the object itself. The actual object resides in its original, or home, context. The proxy is an object that represents the original object in a different context. The static method RemotingServices.IsTransparentProxy determines whether an object reference points to a real object instance or a proxy. Look at the code in the Threading Step 4 example main routine:

 hotelBroker = new HotelBroker();  customers = new Customers();  bool bTrans;  bTrans = RemotingServices.IsTransparentProxy(customers);  Console.WriteLine("Is the customer object a proxy? {0}",                                                  bTrans);  bTrans = RemotingServices.IsTransparentProxy(hotelBroker);   Console.WriteLine("Is the bookings object a proxy? {0}",                                                  bTrans); 

which causes the following output:

 Is the customer object a proxy? False  Is the bookings object a proxy? True 

When a program starts up it is given a default context. [11] All objects, like the Customers object, that do not have any special requirements are created inside that context (context 0). An object, such as the HotelBroker object, that has a different set of requirements (synchronization) is created in a different context (context 1), and a proxy is returned to the creating context (context 0).

[11] As will be clear in the next section, the sentence should really read, "When a new application domain starts up, it is given a new default context." Contexts are application-domain relative. Two different application domains will have two separate default contexts, each with id 0.

Now when you access the MakeReservation method in the HotelBroker object, you are actually accessing a method on the proxy. The proxy method can apply the synchronization lock and then delegate to the actual HotelBroker object's method. When the actual object's method returns, it returns to the proxy. The proxy can then remove the synchronization lock and return to the caller. This technique, where the runtime uses a proxy to intercept method calls to the actual object, is called interception .

ContextBoundObject

The Broker class has to derive from the class ContextBoundObject so that the runtime knows to setup a different context if one is required. If you remove the derivation of Broker from ContextBoundObject , you will once again get the unsynchronized access, and both customers will be able to reserve the last room at the hotel, even though the class is still marked with the Synchronization attribute. Objects that do not derive from ContextBoundObject can run in any context (agile objects).

Since other contexts work with a proxy, or a reference to the actual object, the runtime must translate (marshal) the call from one context to another. Hence, ContextBoundObject inherits from MarshalByRefObject . MarshalByRefObject is the base class for objects that want to be able to be marshaled by reference. Otherwise, as we will discuss in the section on application domains, by default, objects are marshaled by value (i.e., copied ).

One advantage of using synchronization techniques such as a Monitor is that a Monitor can be called from any context. Another potential disadvantage of using automatic synchronization is the performance hit from marshaling and using proxies rather than the actual object.

As will be clear when we discuss Application Domains, since the customer object has no dependency on context, it is the actual object, not a proxy. It can be copied to any context within the same application domain.

for RuBoard


Application Development Using C# and .NET
Application Development Using C# and .NET
ISBN: 013093383X
EAN: 2147483647
Year: 2001
Pages: 158

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net