aboutsummaryrefslogtreecommitdiff
path: root/dep/g3dlite/include/G3D/GMutex.h
blob: 9fe098d10e367bd202545db6af5b4d3483e1e433 (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
/** 
  @file GMutex.h
   
  @created 2005-09-22
  @edited  2009-03-25
 */

#ifndef G3D_GMutex_h
#define G3D_GMutex_h

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

#ifndef G3D_WIN32
#   include <pthread.h>
#   include <signal.h>
#   include <unistd.h>
#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). */
    inline bool lock() {
        bool first = true;
        while (x.compareAndSet(0, 1) == 1) {
            first = false;
#           ifdef G3D_WIN32
                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_WIN32
    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