~ubuntu-branches/ubuntu/trusty/mongodb/trusty-proposed

« back to all changes in this revision

Viewing changes to util/mvar.h

  • Committer: Bazaar Package Importer
  • Author(s): Antonin Kral
  • Date: 2010-01-29 19:48:45 UTC
  • Revision ID: james.westby@ubuntu.com-20100129194845-8wbmkf626fwcavc9
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// mvar.h
 
2
 
 
3
/*    Copyright 2009 10gen Inc.
 
4
 *
 
5
 *    Licensed under the Apache License, Version 2.0 (the "License");
 
6
 *    you may not use this file except in compliance with the License.
 
7
 *    You may obtain a copy of the License at
 
8
 *
 
9
 *    http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 *    Unless required by applicable law or agreed to in writing, software
 
12
 *    distributed under the License is distributed on an "AS IS" BASIS,
 
13
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
 *    See the License for the specific language governing permissions and
 
15
 *    limitations under the License.
 
16
 */
 
17
 
 
18
namespace mongo {
 
19
 
 
20
    /* This is based on haskell's MVar synchronization primitive:
 
21
     * http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.2.0.0/Control-Concurrent-MVar.html
 
22
     *
 
23
     * It is a thread-safe queue that can hold at most one object.
 
24
     * You can also think of it as a box that can be either full or empty.
 
25
     */
 
26
 
 
27
    template <typename T>
 
28
    class MVar {
 
29
    public:
 
30
        enum State {EMPTY=0, FULL};
 
31
 
 
32
        // create an empty MVar
 
33
        MVar()
 
34
          : _state(EMPTY)
 
35
        {}
 
36
 
 
37
        // creates a full MVar
 
38
        MVar(const T& val)
 
39
          : _state(FULL)
 
40
          , _value(val)
 
41
        {}
 
42
 
 
43
        // puts val into the MVar and returns true or returns false if full
 
44
        // never blocks
 
45
        bool tryPut(const T& val){
 
46
            // intentionally repeat test before and after lock
 
47
            if (_state == FULL) return false;
 
48
            Mutex::scoped_lock lock(_mutex);
 
49
            if (_state == FULL) return false;
 
50
 
 
51
            _state = FULL;
 
52
            _value = val;
 
53
 
 
54
            // unblock threads waiting to 'take'
 
55
            _condition.notify_all();
 
56
 
 
57
            return true;
 
58
        }
 
59
 
 
60
        // puts val into the MVar
 
61
        // will block if the MVar is already full
 
62
        void put(const T& val){
 
63
            Mutex::scoped_lock lock(_mutex);
 
64
            while (!tryPut(val)){
 
65
                 // unlocks lock while waiting and relocks before returning
 
66
                _condition.wait(lock);
 
67
            } 
 
68
        }
 
69
 
 
70
        // takes val out of the MVar and returns true or returns false if empty
 
71
        // never blocks
 
72
        bool tryTake(T& out){
 
73
            // intentionally repeat test before and after lock
 
74
            if (_state == EMPTY) return false;
 
75
            Mutex::scoped_lock lock(_mutex);
 
76
            if (_state == EMPTY) return false;
 
77
 
 
78
            _state = EMPTY;
 
79
            out = _value;
 
80
 
 
81
            // unblock threads waiting to 'put'
 
82
            _condition.notify_all();
 
83
 
 
84
            return true;
 
85
        }
 
86
 
 
87
        // takes val out of the MVar
 
88
        // will block if the MVar is empty
 
89
        T take(){
 
90
            T ret = T();
 
91
 
 
92
            Mutex::scoped_lock lock(_mutex);
 
93
            while (!tryTake(ret)){
 
94
                 // unlocks lock while waiting and relocks before returning
 
95
                _condition.wait(lock);
 
96
            } 
 
97
 
 
98
            return ret;
 
99
        }
 
100
 
 
101
 
 
102
        // Note: this is fast because there is no locking, but state could
 
103
        // change before you get a chance to act on it.
 
104
        // Mainly useful for sanity checks / asserts.
 
105
        State getState(){ return _state; }
 
106
 
 
107
 
 
108
    private:
 
109
        State _state;
 
110
        T _value;
 
111
        typedef boost::recursive_mutex Mutex;
 
112
        Mutex _mutex;
 
113
        boost::condition _condition;
 
114
    };
 
115
 
 
116
}