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