Index
An application singleton design pattern has a single process running an application. Starting another application process results in some action in the initial process, and the new process takes no further action. Effectively, only one instance of the application runs at any tiven time, and starting the application again results in some appropriate action, like opening a new window or a file, with the second process terminating and not taking any action. With an application singleton design pattern, a single process executes the action defined by running another application process.
#include <x/singletonapp.H> class singletonThreadObj : virtual public x::obj { public: singletonThreadObj(); ~singletonThreadObj(); void run(const x::fd &connection) { x::singletonapp::validate_peer(connection); // ... } }; typedef x::ref<singletonThreadObj> singletonThread; class threadFactoryObj : virtual public x::obj { public: threadFactoryObj(); ~threadFactoryObj(); singletonThread new_thread() { return singletonThread::create(); } }; int main() { auto factory=x::ref<threadFactoryObj>::create(); x::singletonapp::instance instance=x::singletonapp::create(factory); x::fd connection=instance->connection; x::singletonapp::validate_peer(connection); return 0; }
x::singletonapp
implements an application singleton design pattern by, essentially,
establishing socket connections from multiple processes that run the same
application to individual threads within a single process, which forms the
singleton.
The argument to x::singletonapp::create
() is your
thread factory.
Your thread factory implements the new_thread
()
method. It returns a reference
to an object with a run
() that takes a file
descriptor as an argument.
Your new_thread
() does not run a new thread, only
constructs a new object. Each call to new_thread
()
must construct a new object. new_thread
() must not
return the same object for each thread. Furthermore, no other references
to the constructed object must remain in scope. After the thread object's
run
() returns, it's expected that no other
references to the object exist and the object gets destroyed.
An application singleton process constructs the factory object,
and calls x::singletonapp::create
().
This function returns an
x::singletonapp::instance
with a connection
member which is a file descriptor
of an open socket.
If this is the first application process,
x::singletonapp::create
() calls
new_thread
(), followed by
x::run
to start
a new thread running the thread object's run
(),
with a socket that's connected to the connection
in the
x::singletonapp::instance
.
If there's already an existing process running this application,
the factory object that's created in the new process is not used. The
existing process's factory object invokes
new_thread
(), and the new thread that executes
the resulting object's run
() gets a socket that's
connected to the socket in the other process's
connection
.
The scope of
x::singletonapp
is limited to establishing socket connections from multiple processes
running the same application to multiple threads running in a first
process that's running the application. Once the sockets are established,
x::singletonapp
's job is done.
It's expected that a singleton
process's main
() uses the socket to send the
application startup parameters, commands, options, and similar
information to its peer thread, and then terminate immediately
(or, have managed
()
take care of it, as described later).
If this is the first application process, that started the first thread,
x::singletonapp::instance
's destructor waits
until all threads have stopped. If this is not the first application
process, there are no threads to wait for, and the instance object gets
destroyed immediately, and main
() returns.
If, before the first thread terminated, another process resulted in the
first application process starting a new singleton thread, the
x::singletonapp::instance
's destructor in
the first process keeps waiting until all threads stop, then finishes
destroying the instance object, the first process finally terminates,
and the singleton is now permanently stopped.
The previous example has a short
main
() that instantiates a
x::singletonapp::instance
reference.
Presumably the ommited part of main
()
sends startup parameters to the first singleton threads, then exits
the scope. At this point, the destructor's instance waits for all
singleton threads to stop. Any new threads, started as a result of
connections from other singleton processes, will also have to stop,
before the destructor in the first process completes.
In other application processes, there are no threads to stop, and the destructor completes immediately (and the factory object does not get used, in those processes).