KSquare Utilities
KKB::GoalKeeper Class Reference

#include <GoalKeeper.h>

Public Types

typedef GoalKeeperGoalKeeperPtr
 

Public Member Functions

bool Blocked ()
 Will return true if any thread lock on this instance of "GoalKeeper". More...
 
bool BlockedByAnotherThread ()
 Returns true if a different thread has this instance of "GoalKeeper" locked. More...
 
kkint32 BlockerThreadId ()
 ThreadId of thread that currently holds the Block -1 indicates no Block. More...
 
void EndBlock ()
 Ends the block and allows other threads to pass through StatBlock. More...
 
kkint32 MemoryConsumedEstimated () const
 
const KKStrName () const
 
kkint32 NumBlockedThreads ()
 Returns the number of threads that are waiting to establish a lock on this instance. More...
 
void StartBlock ()
 Initiates a Block as long as another thread has not already locked this object. More...
 

Static Public Member Functions

static void Create (const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper)
 Create a GoalKeeper object and avoid a race condition doing it. More...
 
static void CreateAndStartBlock (const KKStr &_name, volatile GoalKeeperPtr &_newGoalKeeper, bool &_didNotExistYet)
 Create a GoalKeeper object and avoid a race condition doing it. More...
 
static void Destroy (volatile GoalKeeperPtr &_goalKeeperInstance)
 Destroys an existing instance of GoalKeeper. More...
 
static void FinalCleanUp ()
 Will be registered with 'atexit' so that it will be called when program is unloaded from memory. More...
 

Friends

class KKQueue< GoalKeeper >
 

Detailed Description

Definition at line 38 of file GoalKeeper.h.

Member Typedef Documentation

Definition at line 41 of file GoalKeeper.h.

Member Function Documentation

bool GoalKeeper::Blocked ( )

Will return true if any thread lock on this instance of "GoalKeeper".

Definition at line 173 of file GoalKeeper.cpp.

174 {
175  return blocked;
176 } /* Blocked */
bool GoalKeeper::BlockedByAnotherThread ( )

Returns true if a different thread has this instance of "GoalKeeper" locked.

GoalKeeper keeps track of which thread has a lock on this instance of 'GoalKeeper'. This way we know if the calling thread is not the one to have a lock on the thread.

Definition at line 180 of file GoalKeeper.cpp.

References KKB::osGetThreadId().

181 {
182  if (!blocked)
183  return false;
184 
185  kkint32 curThreadId = KKB::osGetThreadId ();
186  return (blocked && (curThreadId != blockerThreadId));
187 }
__int32 kkint32
Definition: KKBaseTypes.h:88
kkint32 osGetThreadId()
kkint32 GoalKeeper::BlockerThreadId ( )

ThreadId of thread that currently holds the Block -1 indicates no Block.

Definition at line 588 of file GoalKeeper.cpp.

589 {
590  kkint32 x = 0;
591  x = blockerThreadId;
592  return x;
593 }
__int32 kkint32
Definition: KKBaseTypes.h:88
void GoalKeeper::Create ( const KKStr _name,
volatile GoalKeeperPtr _newGoalKeeper 
)
static

Create a GoalKeeper object and avoid a race condition doing it.

In case two different threads try to create the same GoalKeeper at the same time you only want one of them to succeed and the other to use same GaolKeeper object.

Parameters
[in]_nameName of Goal Keeper object that you want to create.
[in,out]_newGoalKeeperYou pass this in. Create will block out the critical region that creates the GoalKeeper object. If it was already created, that is != NULL will just return not changing its value. If it is still NULL in the critical section it will create a new instance and set this parameter to its address.

< default security attributes

< initially not owned

Definition at line 346 of file GoalKeeper.cpp.

References KKB::GoalKeeperList::GoalKeeperList().

Referenced by KKLSC::ScannerFile::CreateGoalie(), KKB::Raster::Initialize(), KKB::RasterBuffer::RasterBuffer(), and KKLSC::ScannerHeaderFields::ScannerHeaderFields().

349 {
350 #if defined(WIN32)
351  HANDLE mutexCreateHandle = CreateMutex (NULL, /**< default security attributes */
352  false, /**< initially not owned */
353  "GoalKeeperClass"
354  );
355  if (mutexCreateHandle == NULL)
356  throw KKException ("GoalKeeper::Create failed to get handle to Mutex Object 'GoalKeeperClass'.");
357 
358  WaitForSingleObject (mutexCreateHandle, INFINITE);
359 
360  if (_newGoalKeeper == NULL)
361  {
362  _newGoalKeeper = new GoalKeeper (_name);
363  if (existingGoalKeepers == NULL)
364  {
365  existingGoalKeepers = new GoalKeeperList (true);
366  atexit (GoalKeeper::FinalCleanUp);
367  }
368  existingGoalKeepers->PushOnBack (_newGoalKeeper);
369  }
370 
371  ReleaseMutex (mutexCreateHandle);
372  CloseHandle(mutexCreateHandle);
373 #else
374  sem_t* semHandle = sem_open ("GoalKeeperClass", O_CREAT, 0644, 1);
375  if (semHandle == SEM_FAILED)
376  {
377  cout << std::endl
378  << "GoalKeeper::Create Error[" << errno << "] opening '/GoalKeeper' Semaphore." << std::endl
379  << std::endl;
380 
381  perror("GoalKeeper::Create Error Opening Semaphore 'GoalKeeper'");
382 
383  throw "GoalKeeper::Create Error opening 'GoalKeeper'.";
384  }
385 
386  sem_wait (semHandle);
387 
388  if (_newGoalKeeper == NULL)
389  {
390  _newGoalKeeper = new GoalKeeper (_name);
391  if (existingGoalKeepers == NULL)
392  {
393  existingGoalKeepers = new GoalKeeperList (true);
394  atexit (GoalKeeper::FinalCleanUp);
395  }
396  existingGoalKeepers->PushOnBack (_newGoalKeeper);
397  }
398 
399  sem_post (semHandle);
400  sem_close (semHandle);
401 #endif
402 } /* Create */
HTMLReport &__cdecl endl(HTMLReport &htmlReport)
Definition: HTMLReport.cpp:240
virtual void PushOnBack(EntryPtr _entry)
Definition: KKQueue.h:398
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
void GoalKeeper::CreateAndStartBlock ( const KKStr _name,
volatile GoalKeeperPtr _newGoalKeeper,
bool &  _didNotExistYet 
)
static

Create a GoalKeeper object and avoid a race condition doing it.

Create a new instance of a GoalKeeper object if it has not already been done and locks it if we create it.

Similar to 'Create' except it will also call the StartBlock method. There is also an additional parameter that will let you know if your call was responsible for creating it.

In case two different threads try to create the same GoalKeeper at the same time you only want one of them to succeed and the other to use same GaolKeeper object.

Parameters
[in]_nameName of Goal Keeper object that you want to create.
[in,out]_newGoalKeeperYou pass this in. Create will block out the critical region that creates the GoalKeeper object. If it was already created, that is != NULL will just return not changing its value. If it is still NULL in the critical section it will create a new instance and set this parameter to its address.
[out]_didNotExistYetIndicates if this call had to create the GoalKeeper instance; if it already existed will return as false.
[in]_nameName to be assigned to GoalKeeper object.
[in,out]_newGoalKeeperA pointer to the GoalKeeper that already exists or to new one that got created.
[out]_didNotExistYetIndicates if the call to 'CreateAndStartBlock' had to create a new instance.

< default security attributes.

< initially not owned.

Definition at line 413 of file GoalKeeper.cpp.

References KKB::GoalKeeperList::GoalKeeperList(), and StartBlock().

417 {
418 #if defined(WIN32)
419  HANDLE mutexCreateHandle = CreateMutex (NULL, /**< default security attributes. */
420  false, /**< initially not owned. */
421  "GoalKeeperClass"
422  );
423  if (mutexCreateHandle == NULL)
424  throw KKException("GoalKeeper::CreateAndStartBlock failed to get handle to Mutex Object 'GoalKeeperClass'.");
425 
426  WaitForSingleObject (mutexCreateHandle, INFINITE);
427 
428  if (_newGoalKeeper == NULL)
429  {
430  _didNotExistYet = true;
431  _newGoalKeeper = new GoalKeeper (_name);
432 
433  if (existingGoalKeepers == NULL)
434  {
435  existingGoalKeepers = new GoalKeeperList (true);
436  atexit (GoalKeeper::FinalCleanUp);
437  }
438  existingGoalKeepers->PushOnBack (_newGoalKeeper);
439  }
440  else
441  {
442  _didNotExistYet = false;
443  }
444 
445  _newGoalKeeper->StartBlock ();
446 
447  ReleaseMutex (mutexCreateHandle);
448  CloseHandle(mutexCreateHandle);
449 #else
450  sem_t* semHandle = sem_open ("GoalKeeperClass", O_CREAT, 0644, 1);
451  if (semHandle == SEM_FAILED)
452  {
453  cout << std::endl
454  << "GoalKeeper::Create Error[" << errno << "] opening '/GoalKeeper' Semaphore." << std::endl
455  << std::endl;
456 
457  perror("GoalKeeper::Create Error Opening Semaphore 'GoalKeeper'");
458 
459  throw "GoalKeeper::Create Error opening 'GoalKeeper'.";
460  }
461 
462  sem_wait (semHandle);
463 
464  if (_newGoalKeeper == NULL)
465  {
466  _didNotExistYet = true;
467  _newGoalKeeper = new GoalKeeper (_name);
468  if (existingGoalKeepers == NULL)
469  {
470  existingGoalKeepers = new GoalKeeperList (true);
471  atexit (GoalKeeper::FinalCleanUp);
472  }
473  existingGoalKeepers->PushOnBack (_newGoalKeeper);
474  }
475  else
476  {
477  _didNotExistYet = false;
478  }
479 
480  _newGoalKeeper->StartBlock ();
481 
482  sem_post (semHandle);
483  sem_close (semHandle);
484 #endif
485 } /* CreateAndStartBlock */
HTMLReport &__cdecl endl(HTMLReport &htmlReport)
Definition: HTMLReport.cpp:240
virtual void PushOnBack(EntryPtr _entry)
Definition: KKQueue.h:398
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
void GoalKeeper::Destroy ( volatile GoalKeeperPtr _goalKeeperInstance)
static

Destroys an existing instance of GoalKeeper.

Use this method rather than calling the destructor directly. This way the 'existingGoalKeepers' data member can be kept up to date. If for some reason two different threads managed to call this method for the same GoalKeeper instance only one of them will actually destroy the instance.

Parameters
[in,out]_goalKeeperInstanceInstance of GoalKeeper that is to be destroyed. Upon return it will be set to NULL.

< default security attributes

< initially not owned

Definition at line 491 of file GoalKeeper.cpp.

Referenced by KKMLL::FileDesc::FinalCleanUp(), KKMLL::MLClass::FinalCleanUp(), KKB::Raster::FinalCleanUp(), KKB::RasterBuffer::~RasterBuffer(), KKLSC::ScannerFile::~ScannerFile(), and KKLSC::ScannerHeaderFields::~ScannerHeaderFields().

492 {
493 #if defined(WIN32)
494  HANDLE mutexCreateHandle = CreateMutex (NULL, /**< default security attributes */
495  false, /**< initially not owned */
496  "GoalKeeperClass"
497  );
498  if (mutexCreateHandle == NULL)
499  throw KKException("GoalKeeper::Destroy failed to get handle to Mutex Object 'GoalKeeperClass'.");
500 
501  WaitForSingleObject (mutexCreateHandle, INFINITE);
502 
503  if (_goalKeeperInstance == NULL)
504  {
505  // Some other thread managed to destroy this instance.
506  }
507  else
508  {
509  kkint32 existingInstanceIdx = existingGoalKeepers->PtrToIdx (_goalKeeperInstance);
510  if (existingInstanceIdx < 0)
511  {
512  // If not in list then a different thread beat us to destroying this instance or it was never created to start with.
513  }
514  else
515  {
516  existingGoalKeepers->DeleteEntry (_goalKeeperInstance);
517  delete _goalKeeperInstance;
518  _goalKeeperInstance = NULL;
519  }
520  }
521 
522  ReleaseMutex (mutexCreateHandle);
523  CloseHandle(mutexCreateHandle);
524 #else
525  sem_t* semHandle = sem_open ("GoalKeeperClass", O_CREAT, 0644, 1);
526  if (semHandle == SEM_FAILED)
527  {
528  cout << std::endl
529  << "GoalKeeper::Create Error[" << errno << "] opening '/GoalKeeper' Semaphore." << std::endl
530  << std::endl;
531 
532  perror("GoalKeeper::Create Error Opening Semaphore 'GoalKeeper'");
533 
534  throw "GoalKeeper::Create Error opening 'GoalKeeper'.";
535  }
536 
537  sem_wait (semHandle);
538 
539  if (_goalKeeperInstance == NULL)
540  {
541  // Some other thread managed to destroy this instance.
542  }
543  else
544  {
545  kkint32 existingInstanceIdx = existingGoalKeepers->PtrToIdx (_goalKeeperInstance);
546  if (existingInstanceIdx >= 0)
547  {
548  // If not in list then a different thread beat us to destroying this instance or it was never created to start with.
549  }
550  else
551  {
552  existingGoalKeepers->DeleteEntry (_goalKeeperInstance);
553  delete _goalKeeperInstance;
554  _goalKeeperInstance = NULL;
555  }
556  }
557 
558  sem_post (semHandle);
559  sem_close (semHandle);
560 #endif
561 
562 } /* Destroy */
HTMLReport &__cdecl endl(HTMLReport &htmlReport)
Definition: HTMLReport.cpp:240
__int32 kkint32
Definition: KKBaseTypes.h:88
void DeleteEntry(EntryPtr _entry)
Definition: KKQueue.h:684
kkint32 PtrToIdx(EntryConstPtr _entry) const
Definition: KKQueue.h:761
void GoalKeeper::EndBlock ( )

Ends the block and allows other threads to pass through StatBlock.

Decrements the variable 'blockerDepth' by one. Once 'blockerDepth' is equal zero the Block on this instance is removed. The idea is that for each time in a row a Thread calls StartBlock it has to call EndBlock the same number of times.

Definition at line 295 of file GoalKeeper.cpp.

References KKB::KKStr::Concat(), KKB::KKStr::operator+(), KKB::operator+(), and KKB::osGetThreadId().

Referenced by KKLSC::ScannerHeaderFields::Add(), KKB::RasterBuffer::AddRaster(), KKLSC::ScannerFile::AddStartStopEntryToIndexFile(), KKLSC::ScannerFile::BuildFrameOffsets(), KKMLL::MLClass::ChangeNameOfClass(), KKLSC::ScannerHeaderFields::Clear(), KKMLL::MLClass::CreateNewMLClass(), KKLSC::ScannerFile::DetermineFrameOffsetForFrame(), KKB::GlobalGoalKeeper::EndBlock(), KKLSC::ScannerHeaderFields::EndBlock(), KKLSC::ScannerHeaderFields::FieldExists(), KKMLL::FileDesc::FinalCleanUp(), KKMLL::MLClass::FinalCleanUp(), KKLSC::ScannerFile::FrameRead(), KKB::RasterBuffer::GetCopyOfLastImage(), KKMLL::FileDesc::GetExistingFileDesc(), KKLSC::ScannerFile::GetFrameOffset(), KKLSC::ScannerFile::GetNextLine(), KKB::RasterBuffer::GetNextRaster(), KKLSC::ScannerHeaderFields::GetValue(), KKMLL::MLClass::GlobalClassList(), KKB::Raster::Initialize(), KKLSC::ScannerHeaderFields::MemoryConsumedEstimated(), KKB::RasterBuffer::MemoryConsumedEstimated(), KKMLL::MLClass::ResetAllParentsToAllClasses(), KKLSC::ScannerFile::SkipNextLine(), and KKLSC::ScannerFile::UpdateFrameOffset().

296 {
297  kkint32 curProcessorId = KKB::osGetThreadId ();
298 
299  kkint32 errorCode = 0; // 0=No Error;
300  // 1=There is no Block
301  // 2=Different thread holds the block
302  // 3=Failure to get a lock
303 
304  {
305  CriticalSectionStart ();
306 
307  if (!blocked)
308  {
309  errorCode = 1;
310  }
311 
312  else if (curProcessorId != blockerThreadId)
313  {
314  errorCode = 2;
315  }
316 
317  else
318  {
319  blockerDepth--;
320  if (blockerDepth < 1)
321  {
322  blocked = false;
323  blockerThreadId = -1;
324  blockerDepth = 0;
325  }
326  }
327 
328  CriticalSectionEnd ();
329  }
330 
331  if (errorCode == 0)
332  return;
333 
334  else if (errorCode == 1)
335  throw KKStr ("GoalKeeper::EndBlock Name[" + name + "] There was no block established.");
336 
337  else if (errorCode == 2)
338  throw KKStr ("GoalKeeper::EndBlock Name[" + name + "] ThreadId[" + curProcessorId + "] Currently holds Block; our ThreadId[" + curProcessorId + "]");
339 
340  return;
341 } /* EndBlock */
__int32 kkint32
Definition: KKBaseTypes.h:88
kkint32 osGetThreadId()
void GoalKeeper::FinalCleanUp ( )
static

Will be registered with 'atexit' so that it will be called when program is unloaded from memory.

Definition at line 566 of file GoalKeeper.cpp.

567 {
568  if (existingGoalKeepers)
569  {
570  delete existingGoalKeepers;
571  existingGoalKeepers = NULL;
572  }
573 }
kkint32 GoalKeeper::MemoryConsumedEstimated ( ) const

Definition at line 166 of file GoalKeeper.cpp.

References KKB::KKStr::MemoryConsumedEstimated().

Referenced by KKLSC::ScannerHeaderFields::MemoryConsumedEstimated(), and KKB::RasterBuffer::RasterBuffer().

167 {
168  return (sizeof (GoalKeeper) + name.MemoryConsumedEstimated ());
169 }
kkint32 MemoryConsumedEstimated() const
Definition: KKStr.cpp:766
const KKStr& KKB::GoalKeeper::Name ( ) const
inline

Definition at line 131 of file GoalKeeper.h.

131 {return name;}
kkint32 GoalKeeper::NumBlockedThreads ( )

Returns the number of threads that are waiting to establish a lock on this instance.

Definition at line 579 of file GoalKeeper.cpp.

Referenced by KKLSC::ScannerFile::BuildFrameOffsets().

580 {
581  kkint32 x = 0;
582  x = numBlockedThreads;
583  return x;
584 }
__int32 kkint32
Definition: KKBaseTypes.h:88
void GoalKeeper::StartBlock ( )

Initiates a Block as long as another thread has not already locked this object.

If it is already blocked processor will sleep and then try again. As long as the variable 'blockerDepth'is greater than zero this instance will be considered blocked. Once a thread has the instance blocked it will increment 'blockerDepth' and return to caller.

Definition at line 214 of file GoalKeeper.cpp.

References KKB::osGetThreadId(), and KKB::osSleepMiliSecs().

Referenced by KKLSC::ScannerHeaderFields::Add(), KKB::RasterBuffer::AddRaster(), KKLSC::ScannerFile::AddStartStopEntryToIndexFile(), KKLSC::ScannerFile::BuildFrameOffsets(), KKMLL::MLClass::ChangeNameOfClass(), KKLSC::ScannerHeaderFields::Clear(), CreateAndStartBlock(), KKMLL::MLClass::CreateNewMLClass(), KKLSC::ScannerFile::DetermineFrameOffsetForFrame(), KKLSC::ScannerHeaderFields::FieldExists(), KKMLL::FileDesc::FinalCleanUp(), KKMLL::MLClass::FinalCleanUp(), KKLSC::ScannerFile::FrameRead(), KKB::RasterBuffer::GetCopyOfLastImage(), KKMLL::FileDesc::GetExistingFileDesc(), KKLSC::ScannerFile::GetFrameOffset(), KKLSC::ScannerFile::GetNextLine(), KKB::RasterBuffer::GetNextRaster(), KKLSC::ScannerHeaderFields::GetValue(), KKMLL::MLClass::GlobalClassList(), KKB::Raster::Initialize(), KKLSC::ScannerHeaderFields::MemoryConsumedEstimated(), KKB::RasterBuffer::MemoryConsumedEstimated(), KKMLL::MLClass::ResetAllParentsToAllClasses(), KKLSC::ScannerFile::SkipNextLine(), KKB::GlobalGoalKeeper::StartBlock(), KKLSC::ScannerHeaderFields::StartBlock(), and KKLSC::ScannerFile::UpdateFrameOffset().

215 {
216  kkint32 curThreadId = KKB::osGetThreadId ();
217 
218  bool firstPassThruLoop = true;
219  bool weAreBlocked = true;
220  kkuint32 milliSecsBlocked = 0;
221 
222  while (weAreBlocked)
223  {
224  CriticalSectionStart ();
225 
226  if (firstPassThruLoop)
227  numBlockedThreads++;
228 
229  if (blocked)
230  {
231  if (curThreadId == blockerThreadId)
232  {
233  // We are the thread that already holds the block; so okay for us
234  // to process.
235  blockerDepth++;
236  weAreBlocked = false;
237  numBlockedThreads--;
238  }
239  else
240  {
241  weAreBlocked = true;
242 #if defined(GOALKEEPER_DEBUG)
243  blockedStats->PushOnBack (new BlockedStat (curThreadId, blockerThreadId, milliSecsBlocked, numBlockedThreads));
244 #endif
245  }
246  }
247  else
248  {
249  // No one holds the lock; so we can take it.
250  blocked = true;
251  blockerDepth = 1;
252  blockerThreadId = curThreadId;
253  weAreBlocked = false;
254  numBlockedThreads--;
255  }
256 
257  CriticalSectionEnd ();
258 
259  if (weAreBlocked)
260  {
261  if (milliSecsBlocked < 10)
262  {
263  osSleepMiliSecs (1);
264  milliSecsBlocked++;
265  }
266 
267  else if (milliSecsBlocked < 200)
268  {
269  osSleepMiliSecs (10);
270  milliSecsBlocked += 10;
271  }
272 
273  else if (milliSecsBlocked < 10000)
274  {
275  osSleepMiliSecs (100);
276  milliSecsBlocked += 100;
277  }
278 
279  else
280  {
281  osSleepMiliSecs (400);
282  milliSecsBlocked += 400;
283  }
284  }
285 
286  firstPassThruLoop = false;
287  }
288 
289  return;
290 } /* StartBlock */
__int32 kkint32
Definition: KKBaseTypes.h:88
kkint32 osGetThreadId()
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
void osSleepMiliSecs(kkuint32 numMiliSecs)

Friends And Related Function Documentation

friend class KKQueue< GoalKeeper >
friend

Definition at line 50 of file GoalKeeper.h.


The documentation for this class was generated from the following files: