Programming .NET Components : Marshaling-by-Reference Activation Modes (part 2) - Server-Activated Singleton

8/14/2012 5:41:58 PM

3. Server-Activated Singleton

The server-activated singleton activation mode provides a single, well-known object to all clients. Because the clients connect to a single, well-known object, .NET ignores the client calls to new, even if the singleton object has not yet been created (the .NET runtime in the client app domain has no way of knowing what goes on in the host app domain anyway). The singleton is created when the first client tries to access it. Subsequent client calls to create new objects and subsequent access attempts are all channeled to the same singleton object (see Figure 3). Example 2 demonstrates these points: you can see from the trace output that the constructor is called only once, on the first access attempt, and that obj2 is wired to the same object as obj1.

Example 2. A singleton object is created when first accessed, then used by all clients
public class MySingleton : MarshalByRefObject
   int m_Counter = 0;

   public MySingleton( )
      Trace.WriteLine("MySingleton.MySingleton( )");
   public void TraceCounter( )

//Client-side code:
MySingleton obj1;
MySingleton obj2;
Trace.WriteLine("Before calling obj1 constructor");
obj1 = new MySingleton( );
Trace.WriteLine("After  calling obj1 constructor");
obj1.TraceCounter( ); //Constructor will be called here
obj1.TraceCounter( );
Trace.WriteLine("Before calling obj2 constructor");
obj2 = new MySingleton( );
Trace.WriteLine("After  calling obj2 constructor");
obj2.TraceCounter( );
obj2.TraceCounter( );
Before calling obj1 constructor
After  calling obj1 constructor
MySingleton.MySingleton( )
Before calling obj2 constructor
After  calling obj2 constructor

Because the singleton constructor is only called implicitly by .NET under the covers, a singleton object can't have parameterized constructors. Parameterized constructors are also banned because of an important semantic characteristic of the singleton activation mode: at any given point in time, all clients share the same state of the singleton object (see Figure 3). If parameterized constructors were allowed, different clients could call them with different parameters, which would result in a different

Figure 3. With a server-activated singleton object, all clients share the same well-known object

state for each client. If you try to create a singleton object using a parameterized constructor, .NET throws an exception of type RemotingException.

COM also supported singletons by allowing you to provide a special class factory that always returned the same object. The COM singleton behaved much like a .NET singleton. Using ATL, designating a class as a singleton was done by replacing the default class factory macro with the singleton macro. The main difference between a COM singleton and a .NET singleton is that with .NET, the object becomes a singleton because the host registers it as such. Other hosts can register the same component type as a single-call or client-activated object. With COM, the singleton was always a singleton.

3.1. Using singleton objects

Singleton objects are the sworn enemy of scalability, because a single object can sustain only so many concurrent client calls. Take care before deciding to use a singleton object. Make sure that the singleton will not be a hotspot for scalability and that your design will benefit from sharing the singleton's object state. In general, you should use a singleton object only if it maps well to a true singleton in the application logic, such as a logbook to which all components should log their activities. Other examples are a single communication port or a single mechanical motor. Avoid using a singleton if there is even the slightest chance that the business logic will allow more than one such object in the future (e.g., if a second communication port or another motor may be added). The reason is clear: if your clients all depend on implicitly being connected to the well-known object, and more than one object is available, the clients will suddenly need to have a way to bind to the correct object. This can have severe implications for the application's programming model. Because of these limitations, I recommend that you generally avoid singletons and instead find ways to share the state of the singleton, instead of the singleton object itself. That said, there are cases when using a singleton is a good idea; for example, class factories are usually implemented as singletons.

3.2. Singleton object lifecycle

Once a singleton object is created, it should live forever. That presents a problem to the .NET garbage-collection mechanism, because even if no client presently has a reference to the singleton object, the semantics of the singleton activation mode stipulate that the singleton be kept alive so that future clients can connect to it and its state. .NET uses leasing to keep an object in a different process alive, but once the lease expires, .NET disconnects the singleton object from the remoting infrastructure and eventually garbage-collects it. Thus, you need to explicitly provide the singleton with a long enough (or even infinite) lease. 

A singleton object shouldn't provide a deterministic mechanism to finalize its state, such as implementing IDisposable. If it's possible to deterministically dispose of a singleton object, it will present you with a problem: once disposed of, the singleton object becomes useless. Furthermore, subsequent client attempts to access or create a new singleton will be channeled to the disposed object. A singleton by its very nature implies that it's acceptable to keep the object alive in memory for a long period of time, and therefore there is no need for deterministic finalization. A singleton object should use only a Finalize( ) method (the C# destructor).

It's important to emphasize again that, in principle, you don't need to cross app domains when using the different activation modes. As long as a proxy is present between the client and the marshal-by-reference object, the client can activate the object as single-call or singleton, even if it's in the same app domain. In practice, however, you're likely to use the server-activated single-call and singleton modes only on remote objects.

4. Activation Modes and Synchronization

In a distributed application, the hosting domain registers the objects it's willing to expose, and their activation modes, with .NET. Each incoming client call into the host is serviced on a separate thread from the thread pool. That allows the host to serve remote client calls concurrently and maximize throughput. The question is, what effect does this have on the objects' synchronization requirements?

You can use synchronization domains to synchronize access to remote objects, but bear in mind that synchronization domains can't flow across app domains. If a client creates a remote object that requires synchronization, the object will have a new synchronization domain, even if the remote client was already part of a synchronization domain.

4.1. Client-activated objects and synchronization

Client-activated objects are no different from classic client/server objects with respect to synchronization. If multiple clients share a reference to an object, and the clients can issue calls on multiple threads at the same time, you must provide for synchronization to avoid corrupting the state of the object. It would be best if the locking were encapsulated in the component itself, by using either synchronization domains or manual synchronization. The reason is clear: any client-side locking (e.g., via the lock statement) locks only the proxy, not the object itself. Another noteworthy point has to do with thread affinity: because each incoming call can be on a different thread, the client-activated object should not make any assumptions about the thread it's running on and should avoid mechanisms such as thread-relative static members or thread local storage. This is true even if it's always the same client accessing the object and that client always runs on the same thread.

4.2. Single-call objects and synchronization

In the case of a single-call object, object-state synchronization isn't a problem, because the object's state in memory exists only for the duration of that call and can't be corrupted by other clients. However, synchronization is required when the objects store state between method calls. If you use a database, you have to either explicitly lock the tables or use transactions with the appropriate isolation levels to lock the data. If you use the filesystem, you need to prevent sharing of the files you access while a call is in progress.

4.3. Singleton objects and synchronization

Unlike client-activated objects, the clients of a singleton object may not even be aware they are actually sharing the same object. As a result, synchronization of a singleton object should be enforced on the object side. You can use either a synchronization domain or manual synchronization. Like a client-activated object, a singleton object must avoid thread affinity.

  •  Programming .NET Components : Remoting - Remote Object Types
  •  Active Directory Domain Services 2008 : Seize the RID Master Role, Seize the PDC Emulator Role, Seize the Infrastructure Master Role
  •  Active Directory Domain Services 2008 : Seize the Schema Master Role, Seize the Domain Naming Master Role
  •  Synology DS212+
  •  QNAP TS-219P II Turbo NAS
  •  Netgear Readynas Duo V2
  •  Iomega Storcenter Ix2 Network Storage Cloud Edition
  •  Freecom Silverstore 2-Drive NAS 2TB
  •  IBM WebSphere Process Server 7 : Installing WID on Windows
  •  IBM WebSphere Process Server 7 : WebSphere Integration Developer overview
  •  D-LINK Sharecenter Shadow DNS-325
  •  Choosing A... NAS Device (Part 2)
  •  Choosing A... NAS Device (Part 1)
  •  Buffalo Linkstation Pro 2TB
  •  Collaborating via Blogs and Wikis : Evaluating Wikis for Collaboration
  •  Collaborating via Blogs and Wikis : Evaluating Blogs for Collaboration
  •  Collaborating via Social Networks and Groupware : Evaluating Online Groupware
  •  Collaborating via Social Networks and Groupware : Creating Groups on Social Networks
  •  Programming .NET Components : Remoting - Application Domains (part 2) - The AppDomain Class, The Host App Domain
  •  Programming .NET Components : Remoting - Application Domains (part 1)
    Top 10
    Microsoft .NET : Design Principles and Patterns - From Principles to Patterns (part 2)
    Microsoft .NET : Design Principles and Patterns - From Principles to Patterns (part 1)
    Brother MFC-J4510DW - An Innovative All-In-One A3 Printer
    Computer Planet I7 Extreme Gaming PC
    All We Need To Know About Green Computing (Part 4)
    All We Need To Know About Green Computing (Part 3)
    All We Need To Know About Green Computing (Part 2)
    All We Need To Know About Green Computing (Part 1)
    Master Black-White Copying
    On-Scene Portrait Photography Techniques
    Most View
    Canon EOS 650D - Big Improvements (Part 3)
    A Not So New Competitor
    Accutone Pisces Band Headphones - Clear And Discrete Sound
    Group Test: PCs Running Windows 8 (Part 2)
    Sharepoint 2010 : Maintaining SQL Server in a SharePoint Environment
    Power To The People (Part 3)
    Windows Vista : Programming the Windows Script Host - Programming Objects
    Windows 7 : Maintaining Your System Configuration (part 2) - Creating or Joining a Homegroup & Viewing Hardware Settings
    Lenovo IdeaPad Z480 – The Stylish Idealist
    Some Of The Biggest Brands In The World Had Their Products (Part 6) - Samsung Galaxy Beam, Asus P8Z77-V Pro, OCZ Octane
    SQL Server 2005 : Using Excel (part 2) - Using PivotTables and Charts in Applications and Web Pages
    The Hacked Man (Part 2) - Digital gold: passwords and mail addresses
    How To Specify And Build A Media PC (Part 4)
    JavaScript Patterns : Essentials - Minimizing Globals
    Fashionable Huawei Ascend P1 XL
    Google Nexus 4 - Features Of A High-End Smartphone For Half The Price
    Samsung Galaxy Camera Review – Part1
    Armaggeddon Nighthawk Kai-5 - The Fleldging Nighthawk
    Visual Studio 2010 : Introducing the Visual Studio Extensibility - Building a Visual Studio Package
    Buying Guide – Router (Part 2) - Asus RT-N56U, D-Link DIR-636L, Edimax BR-6428nS, Cisco Linksys EA0