Singleton: Difference between revisions

Content added Content deleted
(added Caché ObjectScript)
Line 292: Line 292:
// The rest of the methods
// The rest of the methods
}</lang>
}</lang>

=={{header|Caché ObjectScript}}==

In Caché, each job runs in a self-contained execution environment (i.e. a separate process instead of a thread). However, it is possible for each process to share data through multidimensional storage (global variables). This is because when the Caché virtual machine starts, it allocates a single, large chunk of shared memory to allow all Caché processes to access this data simultaneously. However, it is the responsibility of the application developer to ensure read and write access to objects is properly co-ordinated (or 'synchronized') between processes to prevent concurrency problems. Also, Caché defines any global variable whose name starts with 'CacheTemp' as being temporary, which means changes are not usually written to disk and are instead maintained within the in-memory buffer pool.

<lang cos>
/// The <CLASS>Singleton</CLASS> class represents a global singleton object that can
/// be instantiated by multiple processes. The 'Get' class method is used to obtain
/// an in-memory object reference and the 'Set' method is used to save any changes to
/// state. See below for an example.
///
/// <EXAMPLE>
/// Set one=##class(Singleton).Get(.sc)
/// Set one.GlobalProperty="Some Value"
/// Set sc=one.Set()
/// </EXAMPLE>
///
/// <p>Please be aware the 'Set' method will only work if no other process has the
/// global singleton object loaded. This class can also be extended.
Class User.Singleton Extends %SerialObject
{

Property GlobalProperty As %String;

ClassMethod Get(Output pStatus As %Status) As Singleton
{
// check if singleton object already instantiated
Set oRef = ""
For {
Set oRef = $ZObjNext(oRef) If oRef = "" Quit
If oRef.%ClassName(1) = ..%ClassName(1) Quit
}
If $IsObject(oRef) Set pStatus = $$$OK Quit oRef
// obtain shared lock for global singleton object
Lock +^CacheTempUser("Singleton", ..%ClassName(1))#"S":1
If '$Test {
Set pStatus = $$$ERROR($$$GeneralError, "Exclusively locked by another process.")
Quit $$$NULLOREF
}
// retrieve global singleton object and deserialise
Set oId = $Get(^CacheTempUser("Singleton", ..%ClassName(1)))
Set oRef = ..%Open(oId,, .pStatus)
// release shared lock if object cannot be opened
If $$$ISERR(pStatus) {
Lock -^CacheTempUser("Singleton", ..%ClassName(1))#"S"
Quit $$$NULLOREF
}
// return in-memory object referernce
Quit oRef
}

Method Set() As %Status
{
// serialise local singleton object if changes have occurred
If ..%ObjectModified()=0 Quit $$$OK
Set sc = ..%GetSwizzleObject(,.oId) If $$$ISERR(sc) Quit sc
// obtain exclusive lock on global singleton object
Lock +^CacheTempUser("Singleton", ..%ClassName(1)):1
If '$Test {
Quit $$$ERROR($$$GeneralError, "Can't save singleton object, locked by another process.")
}
// update global singleton object and release lock
Set ^CacheTempUser("Singleton", ..%ClassName(1)) = oId
Lock -^CacheTempUser("Singleton", ..%ClassName(1))
Quit $$$OK
}

Method %OnClose() As %Status [ Internal ]
{
// reference count for singleton object is now zero, so
// release shared lock on global singleton object
Lock -^CacheTempUser("Singleton", ..%ClassName(1))#"S"
Quit $$$OK
}

Method %OnNew() As %Status [ Internal ]
{
// do not allow constructor method to be called
Quit $$$ERROR($$$GeneralError, "Can't instantiate directly.")
}

Method %OnConstructClone() As %Status [ Internal ]
{
// do not allow singleton object to be cloned
Quit $$$ERROR($$$GeneralError, "Can't clone instance.")
}

}
</lang>

{{out|Examples}}

<pre>
USER>Set one=##class(Singleton).Get()
USER>Set one.GlobalProperty="Some Value"
USER>Set sc=one.Set()
</pre>


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==