aboutsummaryrefslogtreecommitdiff
path: root/dep/g3dlite/include/G3D/GMutex.h
blob: 5676aa4584f08c72b4fe1e786d4191aad54985e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** 
  \file G3D/GMutex.h
   
  \created 2005-09-22
  \edited  2013-04-03
 */

#ifndef G3D_GMutex_h
#define G3D_GMutex_h

#include "G3D/platform.h"
#include "G3D/AtomicInt32.h"
#include "G3D/debugAssert.h"
#include <string>

#ifndef G3D_WINDOWS
#   include <pthread.h>
#   include <signal.h>
#endif

#if defined(G3D_LINUX) || defined(G3D_OSX)
#   include <unistd.h> // For usleep
#endif


namespace G3D {

/**
   \brief A mutual exclusion lock that busy-waits when locking.

   On a machine with one (significant) thread per processor core,
   a Spinlock may be substantially faster than a mutex.

   \sa G3D::GThread, G3D::GMutex, G3D::AtomicInt32
 */
class Spinlock {
private:

    AtomicInt32   x;

public:

    inline Spinlock() : x(0) {}

    /** Busy waits until the lock is unlocked, then locks it
        exclusively.  Returns true if the lock succeeded on the first
        try (indicating no contention). 
        
        Unlike a G3D::GMutex, a single thread cannot re-enter
        Spinlock::lock() that it already locked.
     */
    inline bool lock() {
        bool first = true;
        while (x.compareAndSet(0, 1) == 1) {
            first = false;
#           ifdef G3D_WINDOWS
                Sleep(0);
#           else
                usleep(0);
#           endif
        }
        return first;
    }

    inline void unlock() {
        x.compareAndSet(1, 0);
    }

};

/**
 \brief Mutual exclusion lock used for synchronization.

 @sa G3D::GThread, G3D::AtomicInt32, G3D::Spinlock
*/
class GMutex {
private:
#   ifdef G3D_WINDOWS
    CRITICAL_SECTION                    m_handle;
#   else
    pthread_mutex_t                     m_handle;
    pthread_mutexattr_t                 m_attr;
#   endif

    // Not implemented on purpose, don't use
    GMutex(const GMutex &mlock);
    GMutex &operator=(const GMutex &);
    bool operator==(const GMutex&);

public:
    GMutex();
    ~GMutex();

    /** Locks the mutex or blocks until available. */
    void lock();

    /** Locks the mutex if it not already locked.
        Returns true if lock successful, false otherwise. */
    bool tryLock();

    /** Unlocks the mutex. */
    void unlock();
};


/**
    Automatically locks while in scope.
*/
class GMutexLock {
private:
    GMutex* m;

    // Not implemented on purpose, don't use
    GMutexLock(const GMutexLock &mlock);
    GMutexLock &operator=(const GMutexLock &);
    bool operator==(const GMutexLock&);

public:
    GMutexLock(GMutex* mutex) {
        m = mutex;
        m->lock();
    }

    ~GMutexLock() {
        m->unlock();
    }
};

} // G3D

#endif