Using the risk pointer (hazard pointer) to handle push and pop without lock stacks

Source: Internet
Author: User

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.