KSquare Utilities
GoalKeeper.h
Go to the documentation of this file.
1 /* GoalKeeper.h -- Implements blocking routines to support thread synchronization.
2  * Copyright (C) 1994-2011 Kurt Kramer
3  * For conditions of distribution and use, see copyright notice in KKB.h
4  */
5 #if !defined(_KKU_GOALKEEPER_)
6 #define _KKU_GOALKEEPER_
7 
8 //#define GOALKEEPER_DEBUG
9 
10 
11 #if defined(WIN32)
12 #include <windows.h>
13 #else
14 #include <fcntl.h>
15 #include <semaphore.h>
16 #endif
17 
18 #include "DateTime.h"
19 #include "KKStr.h"
20 
21 namespace KKB
22 {
25 
26  ///<summary> Used to deal with issues related to thread synchronization issues when sharing the same variables. </summary>
27  ///<remarks>
28  /// Use the GoalKeeper::Create method to create an instance of this class. The Create method will ensure
29  /// that two different threads don't accidentally create two different instances of the same GoalKeeper object.<p/>
30  ///
31  /// GoalKeeper has a concept of levels of depth. That is a particular thread may call StartBlock more than once,
32  /// each time doing so it would be one level deeper. In this case it would have to call EndBlock an equal number
33  /// of times to actually release the block. Imagine that you have a function that Starts and Ends a Block but can
34  /// be called from the middle of another function that also Starts and Ends a block on the same GoalKeeper object.<p/>
35  ///
36  /// This class is meant to function the same under Windows or Linux
37  ///</remarks>
38  class GoalKeeper
39  {
40  public:
42 
43  private:
44  ///<summary> Constructs a GoalKeeper object; best to do this via the GoalKeeper::Create method. </summary>
45  GoalKeeper (const KKStr& _name);
46 
47  ~GoalKeeper ();
48 
49  public:
50  friend class KKQueue<GoalKeeper>;
51 
52 
53  /**
54  *@brief Create a GoalKeeper object and avoid a race condition doing it.
55  *@details In case two different threads try to create the same GoalKeeper at the same time you only
56  * want one of them to succeed and the other to use same GaolKeeper object.
57  *@param[in] _name Name of Goal Keeper object that you want to create.
58  *@param[in,out] _newGoalKeeper You pass this in. Create will block out the critical region that
59  * creates the GoalKeeper object. If it was already created, that
60  * is != NULL will just return not changing its value. If it is
61  * still NULL in the critical section it will create a new instance
62  * and set this parameter to its address.
63  */
64  static void Create (const KKStr& _name,
65  volatile GoalKeeperPtr& _newGoalKeeper
66  );
67 
68 
69  /**
70  *@brief Create a GoalKeeper object and avoid a race condition doing it.
71  *@details Similar to 'Create' except it will also call the StartBlock method. There is also
72  * an additional parameter that will let you know if your call was responsible for
73  * creating it.
74  *
75  * In case two different threads try to create the same GoalKeeper at the same time
76  * you only want one of them to succeed and the other to use same GaolKeeper object.
77  *@param[in] _name Name of Goal Keeper object that you want to create.
78  *
79  *@param[in,out] _newGoalKeeper You pass this in. Create will block out the critical region that
80  * creates the GoalKeeper object. If it was already created, that
81  * is != NULL will just return not changing its value. If it is
82  * still NULL in the critical section it will create a new instance
83  * and set this parameter to its address.
84  *
85  *@param[out] _didNotExistYet Indicates if this call had to create the GoalKeeper instance; if it
86  * already existed will return as false.
87  */
88  static void CreateAndStartBlock (const KKStr& _name,
89  volatile GoalKeeperPtr& _newGoalKeeper,
90  bool& _didNotExistYet
91  );
92 
93  /**
94  *@brief Destroys an existing instance of GoalKeeper.
95  *@details Use this method rather than calling the destructor directly. This way the
96  * 'existingGoalKeepers' data member can be kept up to date. If for some reason two
97  * different threads managed to call this method for the same GoalKeeper instance only
98  * one of them will actually destroy the instance.
99  *@param[in,out] _goalKeeperInstance Instance of GoalKeeper that is to be destroyed. Upon return
100  * it will be set to NULL.
101  */
102  static void Destroy (volatile GoalKeeperPtr& _goalKeeperInstance);
103 
104 
105  /**
106  *@brief Will return true if any thread lock on this instance of "GoalKeeper".
107  */
108  bool Blocked ();
109 
110 
111  /**
112  *@brief Returns true if a different thread has this instance of "GoalKeeper" locked.
113  *@details GoalKeeper keeps track of which thread has a lock on this instance of 'GoalKeeper'.
114  * This way we know if the calling thread is not the one to have a lock on the thread.
115  */
116  bool BlockedByAnotherThread ();
117 
118 
119  kkint32 BlockerThreadId (); /**< @brief ThreadId of thread that currently holds the Block -1 indicates no Block */
120 
121  /**
122  *@brief Ends the block and allows other threads to pass through StatBlock.
123  *@details Decrements the variable 'blockerDepth' by one. Once 'blockerDepth' is equal zero
124  * the Block on this instance is removed. The idea is that for each time in a row a Thread
125  * calls StartBlock it has to call EndBlock the same number of times.
126  */
127  void EndBlock ();
128 
130 
131  const KKStr& Name () const {return name;}
132 
133 
134  /** @brief Returns the number of threads that are waiting to establish a lock on this instance. */
136 
137 
138  /**
139  *@brief Initiates a Block as long as another thread has not already locked this object.
140  *@details If it is already blocked processor will sleep and then try again. As long as the variable
141  * 'blockerDepth'is greater than zero this instance will be considered blocked. Once a thread has the
142  * instance blocked it will increment 'blockerDepth' and return to caller.
143  */
144  void StartBlock ();
145 
146  /**
147  *@brief Will be registered with 'atexit' so that it will be called when program is unloaded from memory
148  */
149  static void FinalCleanUp ();
150 
151  private:
152  void CriticalSectionStart ();
153 
154  void CriticalSectionEnd ();
155 
156 
157  volatile bool blocked; /**< @brief 'true' = Currently Blocked. */
158 
159  kkint32 blockerDepth; /**< @brief Indicates how many times the thread that currently holds the block has
160  * called "StartBlock". For every time the thread that holds the Block calls
161  * "StartBlock" it will have to call "EndBlock" before the block is actually
162  * released.
163  */
164 
165  kkint32 blockerThreadId; /**< @brief ThreadId of thread that currently holds the Block -1 indicates no Block */
166 
167  KKStr name;
168 
169  kkint32 numBlockedThreads; /**< @brief The number of threads waiting in 'StartBlock' for the current block to end */
170 
171  static GoalKeeperListPtr existingGoalKeepers;
172 
173 #if defined(GOALKEEPER_DEBUG)
174  class BlockedStat;
175  typedef BlockedStat* BlockedStatPtr;
176  class BlockedStatList;
178 
180  void ReportBlockedStats ();
181 #endif
182 
183 #if defined(WIN32)
184  CRITICAL_SECTION cs;
185 #else
187 #endif
188 
189  }; /* GoalKeeper */
190 
191  typedef GoalKeeper::GoalKeeperPtr GoalKeeperPtr;
192 
193 #define _GoalKeeper_Defined_
194 
196  {
197  public:
199 
201  {}
202  };
203 
204 
205 }
206 
207 #endif
GoalKeeper * GoalKeeperPtr
Definition: GoalKeeper.h:41
__int32 kkint32
Definition: KKBaseTypes.h:88
kkint32 BlockerThreadId()
ThreadId of thread that currently holds the Block -1 indicates no Block.
Definition: GoalKeeper.cpp:588
static void CreateAndStartBlock(const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper, bool &_didNotExistYet)
Create a GoalKeeper object and avoid a race condition doing it.
Definition: GoalKeeper.cpp:413
static void Destroy(volatile GoalKeeperPtr &_goalKeeperInstance)
Destroys an existing instance of GoalKeeper.
Definition: GoalKeeper.cpp:491
kkint32 MemoryConsumedEstimated() const
Definition: GoalKeeper.cpp:166
const KKStr & Name() const
Definition: GoalKeeper.h:131
bool Blocked()
Will return true if any thread lock on this instance of "GoalKeeper".
Definition: GoalKeeper.cpp:173
static void Create(const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper)
Create a GoalKeeper object and avoid a race condition doing it.
Definition: GoalKeeper.cpp:346
GoalKeeperList(bool _owner)
Definition: GoalKeeper.h:198
KKTHread * KKTHreadPtr
void StartBlock()
Initiates a Block as long as another thread has not already locked this object.
Definition: GoalKeeper.cpp:214
void EndBlock()
Ends the block and allows other threads to pass through StatBlock.
Definition: GoalKeeper.cpp:295
static KKStr Concat(const std::vector< std::string > &values)
Concatenates the list of &#39;std::string&#39; strings.
Definition: KKStr.cpp:1082
static void FinalCleanUp()
Will be registered with &#39;atexit&#39; so that it will be called when program is unloaded from memory...
Definition: GoalKeeper.cpp:566
friend std::ostream & operator<<(std::ostream &os, const Matrix &matrix)
kkint32 NumBlockedThreads()
Returns the number of threads that are waiting to establish a lock on this instance.
Definition: GoalKeeper.cpp:579
GoalKeeperList * GoalKeeperListPtr
Definition: GoalKeeper.h:23
bool BlockedByAnotherThread()
Returns true if a different thread has this instance of "GoalKeeper" locked.
Definition: GoalKeeper.cpp:180