00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_concurrent_priority_queue_H
00030 #define __TBB_concurrent_priority_queue_H
00031
00032 #include "atomic.h"
00033 #include "cache_aligned_allocator.h"
00034 #include "tbb_exception.h"
00035 #include "tbb_stddef.h"
00036 #include "tbb_profiling.h"
00037 #include "internal/_aggregator_impl.h"
00038 #include <vector>
00039 #include <iterator>
00040 #include <functional>
00041
00042 namespace tbb {
00043 namespace interface5 {
00044
00045 using namespace tbb::internal;
00046
00048 template <typename T, typename Compare=std::less<T>, typename A=cache_aligned_allocator<T> >
00049 class concurrent_priority_queue {
00050 public:
00052 typedef T value_type;
00053
00055 typedef T& reference;
00056
00058 typedef const T& const_reference;
00059
00061 typedef size_t size_type;
00062
00064 typedef ptrdiff_t difference_type;
00065
00067 typedef A allocator_type;
00068
00070 explicit concurrent_priority_queue(const allocator_type& a = allocator_type()) : mark(0), my_size(0), data(a)
00071 {
00072 my_aggregator.initialize_handler(my_functor_t(this));
00073 }
00074
00076 explicit concurrent_priority_queue(size_type init_capacity, const allocator_type& a = allocator_type()) :
00077 mark(0), my_size(0), data(a)
00078 {
00079 data.reserve(init_capacity);
00080 my_aggregator.initialize_handler(my_functor_t(this));
00081 }
00082
00084 template<typename InputIterator>
00085 concurrent_priority_queue(InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
00086 data(begin, end, a)
00087 {
00088 mark = 0;
00089 my_aggregator.initialize_handler(my_functor_t(this));
00090 heapify();
00091 my_size = data.size();
00092 }
00093
00095
00096 explicit concurrent_priority_queue(const concurrent_priority_queue& src) : mark(src.mark),
00097 my_size(src.my_size), data(src.data.begin(), src.data.end(), src.data.get_allocator())
00098 {
00099 my_aggregator.initialize_handler(my_functor_t(this));
00100 heapify();
00101 }
00102
00104
00105 concurrent_priority_queue(const concurrent_priority_queue& src, const allocator_type& a) : mark(src.mark),
00106 my_size(src.my_size), data(src.data.begin(), src.data.end(), a)
00107 {
00108 my_aggregator.initialize_handler(my_functor_t(this));
00109 heapify();
00110 }
00111
00113
00114 concurrent_priority_queue& operator=(const concurrent_priority_queue& src) {
00115 if (this != &src) {
00116 std::vector<value_type, allocator_type>(src.data.begin(), src.data.end(), src.data.get_allocator()).swap(data);
00117 mark = src.mark;
00118 my_size = src.my_size;
00119 }
00120 return *this;
00121 }
00122
00124
00126 bool empty() const { return size()==0; }
00127
00129
00131 size_type size() const { return __TBB_load_with_acquire(my_size); }
00132
00134
00135 void push(const_reference elem) {
00136 cpq_operation op_data(elem, PUSH_OP);
00137 my_aggregator.execute(&op_data);
00138 if (op_data.status == FAILED)
00139 throw_exception(eid_bad_alloc);
00140 }
00141
00143
00146 bool try_pop(reference elem) {
00147 cpq_operation op_data(POP_OP);
00148 op_data.elem = &elem;
00149 my_aggregator.execute(&op_data);
00150 return op_data.status==SUCCEEDED;
00151 }
00152
00154
00157 void clear() {
00158 data.clear();
00159 mark = 0;
00160 my_size = 0;
00161 }
00162
00164
00165 void swap(concurrent_priority_queue& q) {
00166 data.swap(q.data);
00167 std::swap(mark, q.mark);
00168 std::swap(my_size, q.my_size);
00169 }
00170
00172 allocator_type get_allocator() const { return data.get_allocator(); }
00173
00174 private:
00175 enum operation_type {INVALID_OP, PUSH_OP, POP_OP};
00176 enum operation_status { WAIT=0, SUCCEEDED, FAILED };
00177
00178 class cpq_operation : public aggregated_operation<cpq_operation> {
00179 public:
00180 operation_type type;
00181 union {
00182 value_type *elem;
00183 size_type sz;
00184 };
00185 cpq_operation(const_reference e, operation_type t) :
00186 type(t), elem(const_cast<value_type*>(&e)) {}
00187 cpq_operation(operation_type t) : type(t) {}
00188 };
00189
00190 class my_functor_t {
00191 concurrent_priority_queue<T, Compare, A> *cpq;
00192 public:
00193 my_functor_t() {}
00194 my_functor_t(concurrent_priority_queue<T, Compare, A> *cpq_) : cpq(cpq_) {}
00195 void operator()(cpq_operation* op_list) {
00196 cpq->handle_operations(op_list);
00197 }
00198 };
00199
00200 aggregator< my_functor_t, cpq_operation> my_aggregator;
00202 char padding1[NFS_MaxLineSize - sizeof(aggregator< my_functor_t, cpq_operation >)];
00204 size_type mark;
00205 __TBB_atomic size_type my_size;
00206 Compare compare;
00208 char padding2[NFS_MaxLineSize - (2*sizeof(size_type)) - sizeof(Compare)];
00210
00227 std::vector<value_type, allocator_type> data;
00228
00229 void handle_operations(cpq_operation *op_list) {
00230 cpq_operation *tmp, *pop_list=NULL;
00231
00232 __TBB_ASSERT(mark == data.size(), NULL);
00233
00234
00235 while (op_list) {
00236
00237
00238
00239
00240
00241
00242
00243 call_itt_notify(acquired, &(op_list->status));
00244 __TBB_ASSERT(op_list->type != INVALID_OP, NULL);
00245 tmp = op_list;
00246 op_list = itt_hide_load_word(op_list->next);
00247 if (tmp->type == PUSH_OP) {
00248 __TBB_TRY {
00249 data.push_back(*(tmp->elem));
00250 __TBB_store_with_release(my_size, my_size+1);
00251 itt_store_word_with_release(tmp->status, uintptr_t(SUCCEEDED));
00252 } __TBB_CATCH(...) {
00253 itt_store_word_with_release(tmp->status, uintptr_t(FAILED));
00254 }
00255 }
00256 else {
00257 __TBB_ASSERT(tmp->type == POP_OP, NULL);
00258 if (mark < data.size() &&
00259 compare(data[0], data[data.size()-1])) {
00260
00261
00262 *(tmp->elem) = data[data.size()-1];
00263 __TBB_store_with_release(my_size, my_size-1);
00264 itt_store_word_with_release(tmp->status, uintptr_t(SUCCEEDED));
00265 data.pop_back();
00266 __TBB_ASSERT(mark<=data.size(), NULL);
00267 }
00268 else {
00269 itt_hide_store_word(tmp->next, pop_list);
00270 pop_list = tmp;
00271 }
00272 }
00273 }
00274
00275
00276 while (pop_list) {
00277 tmp = pop_list;
00278 pop_list = itt_hide_load_word(pop_list->next);
00279 __TBB_ASSERT(tmp->type == POP_OP, NULL);
00280 if (data.empty()) {
00281 itt_store_word_with_release(tmp->status, uintptr_t(FAILED));
00282 }
00283 else {
00284 __TBB_ASSERT(mark<=data.size(), NULL);
00285 if (mark < data.size() &&
00286 compare(data[0], data[data.size()-1])) {
00287
00288
00289 *(tmp->elem) = data[data.size()-1];
00290 __TBB_store_with_release(my_size, my_size-1);
00291 itt_store_word_with_release(tmp->status, uintptr_t(SUCCEEDED));
00292 data.pop_back();
00293 }
00294 else {
00295 *(tmp->elem) = data[0];
00296 __TBB_store_with_release(my_size, my_size-1);
00297 itt_store_word_with_release(tmp->status, uintptr_t(SUCCEEDED));
00298 reheap();
00299 }
00300 }
00301 }
00302
00303
00304
00305 if (mark<data.size()) heapify();
00306 __TBB_ASSERT(mark == data.size(), NULL);
00307 }
00308
00310 void heapify() {
00311 if (!mark && data.size()>0) mark = 1;
00312 for (; mark<data.size(); ++mark) {
00313
00314 size_type cur_pos = mark;
00315 value_type to_place = data[mark];
00316 do {
00317 size_type parent = (cur_pos-1)>>1;
00318 if (!compare(data[parent], to_place)) break;
00319 data[cur_pos] = data[parent];
00320 cur_pos = parent;
00321 } while( cur_pos );
00322 data[cur_pos] = to_place;
00323 }
00324 }
00325
00327
00328 void reheap() {
00329 size_type cur_pos=0, child=1;
00330
00331 while (child < mark) {
00332 size_type target = child;
00333 if (child+1 < mark && compare(data[child], data[child+1]))
00334 ++target;
00335
00336 if (compare(data[target], data[data.size()-1])) break;
00337 data[cur_pos] = data[target];
00338 cur_pos = target;
00339 child = (cur_pos<<1)+1;
00340 }
00341 data[cur_pos] = data[data.size()-1];
00342 data.pop_back();
00343 if (mark > data.size()) mark = data.size();
00344 }
00345 };
00346
00347 }
00348
00349 using interface5::concurrent_priority_queue;
00350
00351 }
00352
00353 #endif