constexpr size_t maxhazardpointers = -;structhazardpointer{std::atomic<std::thread::id>ID; Std::atomic<void*>pointer;}; Arrayhazardpointers;classhazardpointerowner{Hazardpointer*Hazardpointer; Public: Hazardpointerowner (Consthazardpointerowner&) =Delete; Hazardpointerowner&operator=(Consthazardpointerowner&) =Delete; ~Hazardpointerowner () {Hazardpointer-Pointer.store (nullptr); Hazardpointer-Id.store (Std::thread::id ()); } hazardpointerowner (): Hazardpointer (nullptr) {//Get hazard pointer of this thread. for(size_t i =0; i < maxhazardpointers; ++i) {Std:thread::id oldid; //If A hazard pointer ' s ID is not set,//replace it with the current thread ' s ID. if(Hazardpointers[i].id.compare_exchange_strong (oldid, STD::THIS_THREAD::GET_ID ())) {//Then get the referrence of this hazard pointer.Hazardpointer = &Hazardpointers[i]; Break; } } if(Hazardpointer = =nullptr) { ThrowStd::runtime_error ("No Hazard pointers available"); }} std::atomic<void*>&Getpointer () {returnHazardpointer->pointer; }};std::atomic<void*>&Gethazardpointerforcurrentthread () {//every thread has it ' s own hazard pointer.Thread_localStaticHazardpointerowner Hazard; returnhazard.getpointer ();}//If Other threads has hazard pointer point to P.BOOLIsoutstandinghazardpointer (void*p) { for(size_t i =0; i < maxhazardpointers; ++i) { if(hazardpointers[i].pointer.load () = =p) {return true; } } return false;} Template<typename t>voidDoDelete (void*p) { DeleteStatic_cast<t*>(P);}structdatatoreclaim{void*data; Std::function<void(void*) >deleter; Datatoreclaim*Next; Template<typename t>Datatoreclaim (T*p): Data (P), Deleter (&doDelete<T>), Next (0) {} ~Datatoreclaim () {deleter (data); }};std::atomic<DataToReclaim*>Nodestoreclaim;voidAddtoreclaimlist (datatoreclaim*node) {Node->next =nodestoreclaim.load (); while(!nodestoreclaim.compare_exchange_weak (node->Next, node));} Template<typename t>voidReclaimlater (t*data) {Addtoreclaimlist (NewDatatoreclaim (data));}voiddeletenodeswithouthazards () {//to make sure that get the head of the Reclaim list atomically,//Use the exchange instead of sentence like "Auto current = Nodestoreclaim;"Auto CurrentData =Nodestoreclaim.exchange (nullptr); while(CurrentData! =nullptr) {AutoConstNext = currentdata->Next; if(!isoutstandinghazardpointer (currentdata->data)) { DeleteCurrentData; } Else{reclaimlater (CurrentData); } CurrentData=Next; }}template<typename t>classlockfreestack{Private: structNode {std::shared_ptr<T>data; Node*Next; Node (TConst&value): Data (std::make_shared<T>(value)) {} }; Std::atomic<Node*>Head; Std::atomic<size_t>Threadsinpopcount; Std::atomic<Node*>Tobedeletedchainhead; Static voidDeletenodes (node*nodes) { while(Nodes! =nullptr) {AutoConstNext = nodes->Next; Deletenodes; Nodes=Next; } } voidTryreclaim (node*oldhead) { //If only this thread invoking pop (). if(Threadsinpopcount = =1) {Auto Tobedeletedlist=Tobedeletedchainhead.exchange (nullptr); //Now , if only this thread is in the pop. if(--threadsinpopcount = =0) {deletenodes (tobedeletedlist); } //If Some nodes to be deleted still waiting. Else if(Tobedeletedlist! =nullptr) {Pushlisttodelchain (tobedeletedlist); } DeleteOldhead; } Else{ //If more than one thread in the pop.Pushnodetodelchain (Oldhead); --Threadsinpopcount; } } voidPushlisttodelchain (node*nodes) {Auto last=nodes; while(AutoConstNext = last->next) { Last=Next; } pushlisttodelchain (nodes, last); } voidPushlisttodelchain (node* First, node*Last ) { Last->next =Tobedeletedchainhead; //Put current head of delete chain to the next of the last . //Then let's the first be the head. while(!tobedeletedchainhead.compare_exchange_weak (last->Next, first)); } voidPushnodetodelchain (node*node) {Pushlisttodelchain (node, node); } Public: voidPush (TConst&value) {AutoConstNewNode =NewNode (value); NewNode->next =head.load (); while(!head.compare_exchange_weak (newnode->Next, NewNode)); } std::shared_ptr<T>pop () {Auto& hazardpointer =Gethazardpointerforcurrentthread (); Auto Oldhead=head.load (); Do{Node* Temphead =nullptr; Do{Temphead=Oldhead; Hazardpointer.store (Oldhead); Oldhead=head.load (); } while(Oldhead! =temphead); } while(Oldhead &&!head.compare_exchange_strong (Oldhead, Oldhead->next));//1//If not set it ' s hazard pointer nullptr. //When Sime thread is at '//1 ' 'll cause endless loop.Hazardpointer.store (nullptr); Std::shared_ptr<T>result; if(Oldhead! =nullptr) {Result.swap (oldhead); //shouldn ' t check itself. //So must clear the current thread ' s hazard pointer before. if(Isoutstandinghazardpointer (Oldhead)) {reclaimlater (oldhead); } Else{ DeleteOldhead; } deletenodeswithouthazards (); } }};
Using the risk pointer (hazard pointer) to handle push and pop without lock stacks