Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SharedStaticData.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_SharedStaticData_h_
5#define _Stroika_Foundation_Execution_SharedStaticData_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <mutex>
10
11#include "Stroika/Foundation/Common/Common.h"
13#include "Stroika/Foundation/Memory/Common.h"
14
15/**
16 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
17 *
18 * TODO:
19 * @todo See about static buffer style from ModuleInit - so no NEW operation!
20 *
21 * @todo use static inline members, but right now that causes VS2k17 compiler to crash
22 *
23 * @todo Need example use somewhere, and document why this instaed of c++ magic initializers... (and if not good reason, deprecate)
24 */
25
27
28 /**
29 * SharedStaticData<T> is used to safely create a copy of static data shared among various users
30 * in a thread safe way, and where the shared data goes away when the last reference does, and where
31 * the shared data is lazy constructed.
32 *
33 * This is very similar to have a single static variable of type T, except that instead of
34 * having T constructed at global execution time, and destroyed at global object destruction time,
35 * it happens when the first owner comes into existence and when the last owner goes out of existence.
36 *
37 * For example - if the shared data object creates threads, it can be a problem having this destroyed in
38 * a static (file scope) lifetime.
39 *
40 * \note This is also similar to the @see ModuleInit<> template, except that this is intended to give the
41 * user tighter control over lifetime of the shared data.
42 *
43 * \note Why use this instead of member function returning reference to local static object?
44 * Only real difference here is that this 'shared static' object will be auto-deleted
45 * when the last reference to it is destroyed (as opposed to after we start exiting main for static
46 * data member)
47 *
48 * This can be important, if, for example, the shared object contains Thread objects.
49 *
50 *
51 * \par Example Usage (from HealthFrameWorksServer)
52 * \code
53 * class AuditLogSink {
54 * ...
55 * private:
56 * struct SharedData_;
57 * Execution::SharedStaticData<SharedData_> fSharedData_;
58 * };
59 * struct AuditLogSink::SharedData_ {
60 * Execution::Thread::Ptr fCleanupThread;
61 *
62 * SharedData_ ()
63 * : fCleanupThread (Thread::New (&AuditLogSink::SimpleCleanupThread_))
64 * {
65 * fCleanupThread.SetThreadPriority (Thread::Priority::eLowest);
66 * fCleanupThread.SetThreadName ("AuditTrailCleanupThread"sv);
67 * fCleanupThread.Start ();
68 * }
69 * ~SharedData_ ()
70 * {
71 * fCleanupThread.AbortAndWaitForDone ();
72 * }
73 * };
74 * \endcode
75 *
76 * So then on the first AuditLogSink construction - we construct the cleanup thread, and on the last the
77 * thread is shutdown. If these objects are all created after main, this assures the thread startup/cleanup
78 * is all done after the start of main and before it completes.
79 *
80 * \note Since this object is in its 'default initialized' state with all zeros, it is safe to use before
81 * the start of main (), and doesn't require the complicated inter-depependency managment of the
82 * @ModuleInit code.
83 */
84 template <typename T>
86 public:
87 /**
88 */
90 SharedStaticData (const SharedStaticData&) = delete;
91
92 public:
94
95 public:
96 SharedStaticData& operator= (const SharedStaticData&) = delete;
97
98 public:
99 /**
100 * Return value guaranteed lifetime at least as long as 'this' object.
101 *
102 * Note - though THIS is fully threadsafe, use of the reference T& is only as threadsafe as T itself.
103 */
104 nonvirtual T& Get ();
105 nonvirtual const T& Get () const;
106
107 private:
108 // nb. use mutex instead of atomic<> because must lock sOnceObj_ at same time (block subsequent callers while constructing)
109 inline static conditional_t<kSpinLock_IsFasterThan_mutex, SpinLock, mutex> sMutex_{};
110 inline static unsigned int sCountUses_{};
111 inline static T* sOnceObj_{};
112 // alignas (alignof (T)) byte fOnceObj_Storage_[sizeof (T)]; // avoid actual memory allocation call - since only one of these
113 };
114
115}
116
117/*
118 ********************************************************************************
119 ***************************** Implementation Details ***************************
120 ********************************************************************************
121 */
122#include "SharedStaticData.inl"
123
124#endif /*_Stroika_Foundation_Execution_SharedStaticData_h_*/