00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef EBSTACK_H_
00016 #define EBSTACK_H_
00017
00018 #include "smr.h"
00019
00020 namespace amino {
00027 template<typename T> class StackNode {
00028 public:
00029 T data;
00030 StackNode* next;
00031 StackNode() :
00032 next(NULL) {
00033 }
00034
00035 StackNode(const T& val) :
00036 data(val), next(NULL) {
00037 }
00038 };
00044 template<typename T> class EBStack {
00045 private:
00046 atomic<StackNode<T>*> top;
00047 SMR<StackNode<T> , 1>* mm;
00048
00049
00050 static const int TRY_TIMES = 4;
00051
00052
00053 StackNode<T> TOMB_STONE;
00054 StackNode<T> REMOVED;
00055 StackNode<T> EMPTY;
00056
00057 const int coll_size;
00058 atomic<StackNode<T>*>* coll_pop;
00059 atomic<StackNode<T>*>* coll_push;
00060 atomic<int> position;
00061
00062
00063 bool try_add(StackNode<T>*);
00064
00065 StackNode<T>* try_remove();
00066 int get_rand_position();
00067 void initCollisionArray(int);
00068 void destoryCollisionArray();
00069
00070 public:
00076 EBStack(int num = 8) :
00077 TOMB_STONE(), REMOVED(), EMPTY(), coll_size(num), position() {
00078 top = NULL;
00079 mm = getSMR<StackNode<T> , 1> ();
00080 initCollisionArray(num);
00081 }
00082
00086 ~EBStack() {
00087 StackNode<T> *first = top.load(memory_order_relaxed);
00088 while (first != NULL) {
00089 StackNode<T> *next = first->next;
00090 delete first;
00091 first = next;
00092 }
00093 delete top.load(memory_order_relaxed);
00094 destoryCollisionArray();
00095 }
00096
00097 void push(const T d);
00098 bool pop(T& ret);
00099 bool empty();
00100 int size();
00101 bool peekTop(T& ret);
00102
00103 };
00104
00111 template<typename T> void EBStack<T>::initCollisionArray(int num) {
00112 coll_push = new atomic<StackNode<T>*> [num];
00113 coll_pop = new atomic<StackNode<T>*> [num];
00114 for (int i = 0; i < num; ++i) {
00115 coll_push[i].store(NULL);
00116 coll_pop[i].store(NULL);
00117 }
00118 }
00119
00123 template<typename T> void EBStack<T>::destoryCollisionArray() {
00124
00125
00126
00127 delete[] coll_push;
00128 delete[] coll_pop;
00129 }
00134 template<typename T> int EBStack<T>::get_rand_position() {
00135 return position++ % coll_size;
00136 }
00137
00144 template<typename T> void EBStack<T>::push(T d) {
00145 StackNode<T>* newTop = new StackNode<T> (d);
00146
00147 StackNode<T>* oldTop;
00148 while (true) {
00149
00150 oldTop = top.load(memory_order_relaxed);
00151 newTop->next = oldTop;
00152
00153 if (true == top.compare_swap(oldTop, newTop)) {
00154 break;
00155 }
00156
00157
00158 if (true == try_add(newTop)) {
00159 break;
00160 }
00161 }
00162 }
00163
00167 template<typename T> bool EBStack<T>::try_add(StackNode<T>* node) {
00168 int pos = get_rand_position();
00169
00170 for (int i = 0; i < TRY_TIMES; ++i) {
00171 int index = (pos + i) % coll_size;
00172
00173 StackNode<T>* pop_op = coll_pop[index].load(memory_order_relaxed);
00174
00175
00176
00177 if (pop_op == &TOMB_STONE) {
00178 if (coll_pop[index].compare_swap(pop_op, node)) {
00179 return true;
00180 }
00181 }
00182 }
00183
00184
00185
00186
00187
00188 for (int i = 0; i < TRY_TIMES; ++i) {
00189 int index = (pos + i) % coll_size;
00190 StackNode<T>* push_op = coll_push[index].load(memory_order_relaxed);
00191 if (push_op == NULL) {
00192 if (coll_push[index].compare_swap(push_op, node)) {
00193
00194 while (true) {
00195 push_op = coll_push[index].load(memory_order_relaxed);
00196 if (push_op == node) {
00197 if (coll_push[index].compare_swap(node, NULL)) {
00198
00199 return false;
00200 }
00201 } else {
00202
00203
00204
00205 coll_push[index] = NULL;
00206 return true;
00207 }
00208 }
00209 }
00210 }
00211 }
00212 return false;
00213 }
00214
00222 template<typename T> bool EBStack<T>::pop(T& ret) {
00223 StackNode<T> *oldTop, *newTop = NULL;
00224
00225 while (true) {
00226 oldTop = top.load(memory_order_relaxed);
00227 if (oldTop == NULL) {
00228 return false;
00229 }
00230
00231 mm->employ(0, oldTop);
00232
00233 if (top.load(memory_order_relaxed) != oldTop) {
00234 continue;
00235 }
00236
00237 newTop = oldTop->next;
00238 if (top.compare_swap(oldTop, newTop)) {
00239 break;
00240 }
00241
00242
00243 StackNode<T>* col_ele = try_remove();
00244 if (NULL != col_ele) {
00245 ret = col_ele->data;
00246 return true;
00247 }
00248 }
00249 mm->retire(0);
00250
00251 ret = oldTop->data;
00252 mm->delNode(oldTop);
00253 return true;
00254 }
00255
00259 template<typename T> StackNode<T>* EBStack<T>::try_remove() {
00260 int pos = get_rand_position();
00261 for (int i = 0; i < TRY_TIMES; ++i) {
00262 int index = (pos + i) % coll_size;
00263 StackNode<T>* push_op = coll_push[index].load(memory_order_relaxed);
00264
00265 if (push_op == &EMPTY || push_op == &REMOVED) {
00266 StackNode<T>* pop_op = coll_pop[index].load(memory_order_relaxed);
00267 if (pop_op == NULL) {
00268 if (coll_pop[index].compare_swap(pop_op, &TOMB_STONE)) {
00269
00270 while (true) {
00271 pop_op = coll_pop[index].load(memory_order_relaxed);
00272 if (pop_op != &TOMB_STONE) {
00273 coll_pop[index] = NULL;
00274 return pop_op;
00275 } else {
00276 if (coll_pop[index].compare_swap(pop_op, &EMPTY)) {
00277 return NULL;
00278 }
00279 }
00280 }
00281 }
00282 }
00283 } else {
00284 if (coll_push[index].compare_swap(push_op, &REMOVED)) {
00285 return push_op;
00286 }
00287 }
00288
00289 }
00290
00291
00292 return NULL;
00293 }
00294
00300 template<typename T> bool EBStack<T>::empty() {
00301 return top.load(memory_order_relaxed) == NULL;
00302 }
00303
00310 template<typename T> int EBStack<T>::size() {
00311 int ret = 0;
00312 StackNode<T> *node = top.load(memory_order_relaxed);
00313 while (node != NULL) {
00314 ++ret;
00315 node = node->next;
00316 }
00317 return ret;
00318 }
00319
00329 template<typename T> bool EBStack<T>::peekTop(T& ret) {
00330 StackNode<T>* node = top.load(memory_order_relaxed);
00331 if (node == NULL)
00332 return false;
00333 ret = node->data;
00334 return true;
00335 }
00336
00337 }
00338 #endif