GraphLab: Distributed Graph-Parallel API  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
atomic_add_vector2.hpp
1 /**
2  * Copyright (c) 2009 Carnegie Mellon University.
3  * All rights reserved.
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,
12  * software distributed under the License is distributed on an "AS
13  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14  * express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  *
17  * For more about this software visit:
18  *
19  * http://www.graphlab.ml.cmu.edu
20  *
21  */
22 
23 
24 /**
25  * Also contains code that is Copyright 2011 Yahoo! Inc. All rights
26  * reserved.
27  *
28  * Contributed under the iCLA for:
29  * Joseph Gonzalez ([email protected])
30  *
31  */
32 
33 
34 
35 #ifndef GRAPHLAB_ATOMIC_ADD_VECTOR2_HPP
36 #define GRAPHLAB_ATOMIC_ADD_VECTOR2_HPP
37 
38 
39 #include <vector>
40 
41 
42 #include <graphlab/parallel/pthread_tools.hpp>
43 #include <graphlab/util/lock_free_pool.hpp>
44 
45 
46 
47 namespace graphlab {
48 
49  /**
50  * \TODO DOCUMENT THIS CLASS
51  */
52 
53  template<typename ValueType>
55  public:
56  typedef ValueType value_type;
57 
58  // We needed a second "NULL" pointer value to indicate a value
59  // that is being swapped.
60 #define VALUE_PENDING (value_type*)(size_t)(-1)
61 
62  private:
63  atomic<size_t> joincounter;
64 
65  class atomic_box_type {
66  private:
67  simple_spinlock lock;
68  bool _empty;
69  value_type value;
70  public:
71  atomic_box_type() : _empty(true) { }
72  /** returns true if set for the first time */
73  inline bool set(const value_type& other,
74  value_type& new_value,
75  atomic<size_t>& joincounter) {
76  bool first_set = false;
77  lock.lock();
78  if(!_empty) value += other;
79  else { value = other; first_set = true; }
80  new_value = value;
81  _empty = false;
82  lock.unlock();
83  return first_set;
84  }
85 
86  void clear() {
87  value_type val; test_and_get(val);
88  }
89 
90  bool empty() { return _empty; }
91 
92 
93  inline bool peek(value_type& ret_val) {
94  bool success = false;
95  lock.lock();
96  if(!_empty) {
97  success = true;
98  ret_val = value;
99  }
100  lock.unlock();
101  return success;
102  } // end of peek
103 
104  inline bool test_and_get(value_type& ret_val) {
105  bool success = false;
106  lock.lock();
107  if(!_empty) {
108  success = true;
109  ret_val = value;
110  _empty = true;
111  }
112  lock.unlock();
113  return success;
114  } // end of test_and_get
115 
116  }; // end of atomic_box_type;
117 
118 
119 
120  typedef std::vector< atomic_box_type > atomic_box_vec_type;
121  atomic_box_vec_type atomic_box_vec;
122 
123 
124  /** Not assignable */
125  void operator=(const atomic_add_vector2& other) { }
126 
127 
128  public:
129  /** Initialize the per vertex task set */
130  atomic_add_vector2(size_t num_vertices = 0) :
131  atomic_box_vec(num_vertices) { }
132 
133  /**
134  * Resize the internal locks for a different graph
135  */
136  void resize(size_t num_vertices) {
137  atomic_box_vec.resize(num_vertices);
138  }
139 
140  /** Add a task to the set returning false if the task was already
141  present. */
142  bool add(const size_t& idx,
143  const value_type& val) {
144  ASSERT_LT(idx, atomic_box_vec.size());
145  value_type new_value;
146  return atomic_box_vec[idx].set( val, new_value, joincounter);
147  } // end of add task to set
148 
149 
150  // /** Add a task to the set returning false if the task was already
151  // present. */
152  // bool add_unsafe(const size_t& idx,
153  // const value_type& val) {
154  // ASSERT_LT(idx, atomic_box_vec.size());
155  // return atomic_box_vec[idx].set_unsafe(pool, val, joincounter);
156  // } // end of add task to set
157 
158 
159  bool add(const size_t& idx,
160  const value_type& val,
161  value_type& new_value) {
162  ASSERT_LT(idx, atomic_box_vec.size());
163  return atomic_box_vec[idx].set(val, new_value, joincounter);
164  } // end of add task to set
165 
166 
167 
168  // /** Add a task to the set returning false if the task was already
169  // present. Returns the priority of the task before and after
170  // insertion. If the task did not exist prior to the add,
171  // prev_priority = 0 */
172  // bool add(const size_t& idx,
173  // const value_type& val,
174  // double& prev_priority,
175  // double& new_priority) {
176  // ASSERT_LT(idx, atomic_box_vec.size());
177  // return atomic_box_vec[idx].set( val, prev_priority, new_priority,
178  // joincounter);
179  // } // end of add task to set
180 
181  // bool get_nondestructive_unsafe(const size_t& idx,
182  // value_type& ret_val) {
183  // return atomic_box_vec[idx].get_nondestructive_unsafe(ret_val);
184  // }
185 
186  // bool get_reference_unsafe(const size_t& idx,
187  // value_type*& ret_val) {
188  // return atomic_box_vec[idx].get_reference_unsafe(ret_val);
189  // }
190 
191 
192  bool test_and_get(const size_t& idx,
193  value_type& ret_val) {
194  ASSERT_LT(idx, atomic_box_vec.size());
195  return atomic_box_vec[idx].test_and_get( ret_val);
196  }
197 
198  bool peek(const size_t& idx,
199  value_type& ret_val) {
200  ASSERT_LT(idx, atomic_box_vec.size());
201  return atomic_box_vec[idx].peek(ret_val);
202  }
203 
204  bool empty(const size_t& idx) {
205  return atomic_box_vec[idx].empty();
206  }
207 
208  size_t size() const {
209  return atomic_box_vec.size();
210  }
211 
212  size_t num_joins() const {
213  return joincounter.value;
214  }
215 
216 
217  void clear() {
218  for (size_t i = 0; i < atomic_box_vec.size(); ++i) clear(i);
219  }
220 
221  void clear(size_t i) { atomic_box_vec[i].clear(); }
222 
223  }; // end of vertex map
224 
225 }; // end of namespace graphlab
226 
227 #undef VALUE_PENDING
228 
229 #endif
230