base_thread_lock.hh File Reference

Locking mechanisms to thread code. More...

#include "base_thread_common.hh"

Go to the source code of this file.

Namespaces

namespace  base

Classes

class  base::AutoLock< LOCK >
 Automatically lock/unlock a mutex inside a C++ block. More...
class  base::RushLock
 RushLock is a NON-RECURSIVE spinlock (limited use). More...
class  base::RushLock::Auto
class  base::FastLock
 FastLock is a recursive spinlock. More...
class  base::FastLock::Auto
class  base::SlowLock
 SlowLock is a a recursive locking mechanism for slow functions. More...
class  base::SlowLock::Auto
class  base::NoLock
 NOP lock. More...
class  base::NoLock::Auto

Defines

#define BASE_THREAD_LOCK_HH   1
#define THREAD_AUTO_FAST_LOCK   {{ PERSISTENT FastLock lock; FastLock::Auto autolock(&lock); }}
#define THREAD_AUTO_SLOW_LOCK   {{ PERSISTENT SlowLock lock; SlowLock::Auto autolock(&lock); }}
#define PAUSE_CPU()
#define FAST_LOCK_YIELD(i)


Detailed Description

Locking mechanisms to thread code.

Id
LastChangedDate

Author:
Jim E. Brooks http://www.palomino3d.org
 *
 * Note: Fast/slow describe the speed of the lock itself.
 * SlowLock can greatly speed a program far more than FastLock in some cases.
 *
 * ============
 * Basic locks:
 * ============
 *
 * RushLock:  The fastest lock.  Implemented as a non-recursive spinlock.
 *            Appropriate for:
 *            - Fast self-sufficient routines that NEVER call other routines
 *              guarded by the same lock.
 *            **WARNING** WILL DEAD-LOCK IF SAME THREAD HITS THE SAME LOCK!
 *
 * FastLock:  A recursive spinlock.
 *            Incurs slight overhead because of tracking lock ownersip and lock depth,
 *            but is safer than RushLock and almost as fast.
 *            Appropriate for:
 *            - Fast routines that might call others guarded by the same lock.
 *
 * SlowLock:  A recursive lock that will put contending threads to sleep.
 *            Despite its name and its higher overhead, in certain situations,
 *            it can boost net speed if by allowing a CPU to execute another
 *            thread instead of spinning uselessly as RushLock or FastLock would do.
 *            Appropriate for:
 *            - Functions that execute slowly and often stay locked.
 *
 * NoLock:    For compiling a template class without locking.
 *            An example is Dlist which ordinarily is locked.
 *
 * =========
 * AutoLock:
 * =========
 *
 * AutoLock is intended to lock a method (not a whole class).
 * Limited to being an automatic variable of the method it locks.
 * AutoLock is based on an underlying basic lock.
 * Its ctor and dtor automatically call Lock() and Unlock().
 * AutoLock prevents the mistake of forgetting to call Unlock()
 * or placing a return before Unlock().
 *
 * ================
 * Applying a lock:
 * ================
 *
 * In general terms, a lock is required in a block of code where
 * multiple threads could access the same resource.
 *
 * Questions that determine how to lock:
 * -------------------------------------
 * - What needs locking?
 * - Single or multiple locks?
 * - Which type of locks?
 * - Where to place the locks?
 *
 * IfLocked() vs. TryLock():
 * -------------------------
 * IfLocked() is a query operation.
 * IfLocked() returns true ONLY IF ANOTHER THREAD owns the lock.
 * Returns false for a thread that owns the lock
 * because a thread shouldn't block itself.
 *
 * TryLock() will try to acquire the lock.
 * If TryLock() succeeds, Unlock() should be called afterwards.
 *
 * This is wrong.  TryLock() is correct:
 *
 * if ( mLock.IfLocked() )
 * {
 *     mLock.Lock();  // WRONG: not atomic, causes race-condition
 *     ....
 *     mLock.Unlock();
 * }
 *
 * if ( mLock.TryLock() )
 * {
 *     ...
 *     mLock.Unlock();  // ok, must unlock when done
 * }
 *
 * What needs locking?:
 * --------------------
 *
 * A lock may needed for a method, an instance of a class,
 * or every instance of class, or a combination of these.
 *
 * Single or multiple locks?:
 * --------------------------
 *
 * A C++ class may need locks at different levels.
 * Method-level, instance-level, and class-level locks may be necessary.
 *
 * Consider incrementally developing a List class.
 * Its first requirement is to let two threads to call Prepend() and Remove().
 * Locking those methods with RushLock or FastLock suffices.
 * This is method-level locking.
 *
 * Next its requirements are increased to support traversal by an Iterator.
 * Therefore, the whole instance of the list must be locked (instance-level locking).
 * A SlowLock is probably appropriate since the iteration leads to processing every item.
 *
 * Then profiling becomes a requirement in a debug build.
 * The list class must track how many items are linked in every instance.
 * The count would be stored in a shared class member.
 * A class-level lock is needed to lock-out other instances before updating the count.
 *
 * Which type of lock:
 * -------------------
 -
 * - Decide if a recursive or non-recursive lock is necessary.
 *   Non-recursive locks are dangerous.  Only use them in hi-freq simple routines.
 * - If recursive, select FastLock or SlowLock if a method executes fast or slow, resp.
 *   SlowLock can provide more net speed by allowing the OS to switch a CPU to a ready thread.
 *
 * Where to place the locks?
 * -------------------------
 *
 * Rules for lock placement:
 * 1. Basic locks must be placed in persistent memory.
 * 2. AutoLock objects must be placed on call stack (as an automatic var of a method).
 *
 * Deadlock versus locking bottlenecks:
 * ------------------------------------
 * What may appear to be caused by deadlock may be a locking bottleneck instead.
 * An actual example: Random class had a FastLock while up to 256 threads were run
 * to generate terrain colormap textures.  Texels were computed using Random.
 * That of course resulted in extreme lock contention at Random, which falsely
 * appeared to be a deadlock problem (solved by using rand_r() which needs no locking).
 *
 * System notes:
 * -------------
 *
 * GNU glibc (2.5+) has an extremely fast pthread_self() function
 * which compiles as a "mov reg, gs:[tid]" x86 instruction.
 *
 * 

Define Documentation

#define BASE_THREAD_LOCK_HH   1

#define FAST_LOCK_YIELD (  ) 

Value:

{                                                                                   \
        PAUSE_CPU();                                                                    \
        ++i;                                                                            \
        if ( UX( i > base::defs::FAST_LOCK_LOOP_YIELD ) )                               \
        {                                                                               \
            /* pragma: Thread depends on Lock so use THREAD_YIELD() macro. */           \
            i = 0;                                                                      \
            THREAD_YIELD();                                                             \
        }                                                                               \
    }

 
#define PAUSE_CPU (  ) 

#define THREAD_AUTO_FAST_LOCK   {{ PERSISTENT FastLock lock; FastLock::Auto autolock(&lock); }}

#define THREAD_AUTO_SLOW_LOCK   {{ PERSISTENT SlowLock lock; SlowLock::Auto autolock(&lock); }}

Palomino 3D Engine documents generated by doxygen 1.5.3 on Fri Nov 23 11:26:14 2007