MongoDB  2.7.0
mvar.h
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 #pragma once
19 
20 #include <boost/thread/recursive_mutex.hpp>
21 #include <boost/thread/condition.hpp>
22 
23 namespace mongo {
24 
25  /* This is based on haskell's MVar synchronization primitive:
26  * http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html
27  *
28  * It is a thread-safe queue that can hold at most one object.
29  * You can also think of it as a box that can be either full or empty.
30  */
31 
32  template <typename T>
33  class MVar {
34  public:
35  enum State {EMPTY=0, FULL};
36 
37  // create an empty MVar
38  MVar()
39  : _state(EMPTY)
40  {}
41 
42  // creates a full MVar
43  MVar(const T& val)
44  : _state(FULL)
45  , _value(val)
46  {}
47 
48  // puts val into the MVar and returns true or returns false if full
49  // never blocks
50  bool tryPut(const T& val) {
51  // intentionally repeat test before and after lock
52  if (_state == FULL) return false;
53  Mutex::scoped_lock lock(_mutex);
54  if (_state == FULL) return false;
55 
56  _state = FULL;
57  _value = val;
58 
59  // unblock threads waiting to 'take'
60  _condition.notify_all();
61 
62  return true;
63  }
64 
65  // puts val into the MVar
66  // will block if the MVar is already full
67  void put(const T& val) {
68  Mutex::scoped_lock lock(_mutex);
69  while (!tryPut(val)) {
70  // unlocks lock while waiting and relocks before returning
71  _condition.wait(lock);
72  }
73  }
74 
75  // takes val out of the MVar and returns true or returns false if empty
76  // never blocks
77  bool tryTake(T& out) {
78  // intentionally repeat test before and after lock
79  if (_state == EMPTY) return false;
80  Mutex::scoped_lock lock(_mutex);
81  if (_state == EMPTY) return false;
82 
83  _state = EMPTY;
84  out = _value;
85 
86  // unblock threads waiting to 'put'
87  _condition.notify_all();
88 
89  return true;
90  }
91 
92  // takes val out of the MVar
93  // will block if the MVar is empty
94  T take() {
95  T ret = T();
96 
97  Mutex::scoped_lock lock(_mutex);
98  while (!tryTake(ret)) {
99  // unlocks lock while waiting and relocks before returning
100  _condition.wait(lock);
101  }
102 
103  return ret;
104  }
105 
106 
107  // Note: this is fast because there is no locking, but state could
108  // change before you get a chance to act on it.
109  // Mainly useful for sanity checks / asserts.
110  State getState() { return _state; }
111 
112 
113  private:
114  State _state;
115  T _value;
116  typedef boost::recursive_mutex Mutex;
117  Mutex _mutex;
118  boost::condition _condition;
119  };
120 
121 }
Definition: mvar.h:33
LogstreamBuilder out()
Synonym for log().
Definition: log.h:79