Template<typename t>classlockfreestack{Private: structNode; structCountednode {intExternalcount =0; Node* ptr =nullptr; }; structNode {std::shared_ptr<T>data; Std::atomic<int>Internalcount; Countednode Next; Node (TConst&data_): Data (std::make_shared<T>(Data_)), Internalcount (0) {} }; Std::atomic<CountedNode>Head; voidIncreaseheadcount (countednode&oldcounter) {Countednode newcounter; Do{Newcounter=Oldcounter; ++Newcounter.externalcount; } while(!Head.compare_exchange_strong (Oldcounter, Newcounter, std::memory_order_a Cquire, std::memory_order_relaxed)); Oldcounter.externalcount=Newcounter.externalcount; } Public: ~Lockfreestack () { while(POP ()! =nullptr); } voidPush (TConst&data) {Countednode NewNode; Newnode.ptr=NewNode (data); Newnode.externalcount=1; Newnode.ptr->next =head.load (std::memory_order_relaxed); while(!head.compare_exchange_weak (newnode.ptr->Next, NewNode, Std::memory_order_release, std::memory_order_relaxed)); } std::shared_ptr<T>pop () {Auto Oldhead=head.load (std::memory_order_relaxed); for(;;) {Increaseheadcount (oldhead); AutoConstNodeptr =oldhead.ptr; if(Nodeptr = =nullptr) { returnShared_ptr<t>(); } if(Head.compare_exchange_strong (Oldhead, nodeptr->Next, std::memory_order_relaxed)) {Std::shared_ptr<T>result; Result.swap (Nodeptr-data); int ConstIncreasecount = Oldhead.externalcount-2; if(nodeptr->Internalcount.fetch_add (Increasecount, Std::memory_order_release) == -Increasecount) { Deletenodeptr; } returnresult; } Else if(Nodeptr->internalcount.fetch_add (-1, Std::memory_order_acquire)==1) {nodeptr-internalcount.load (Std::memory_order_acquire); Deletenodeptr; } } }};
To test its correctness, I used the following code as an experiment:
lockfreestack<int>Stack; Std::thread T1 ([&] { for(inti =0; I < -; ++i) { ifI2==0) {Stack.push (i); } Else{AutoConstresult =Stack.pop (); if(Result! =nullptr) {cout<< *result <<" "; } } } }); Std::thread T2 ([&] { for(inti = -; I < $; ++i) {Stack.push (i); } }); std::thread T3 ([&] { for(inti =0; I <199; ++i) {AutoConstresult =Stack.pop (); if(Result! =nullptr) {cout<< *result <<" "; } } }); T1.join (); T2.join (); T3.join ();
The output was very strange, many thousand of thousands of numbers, I once thought is the stack implementation problem, until I replaced the cout with printf ...
Implementation of the lock-free stack