Reclaim Hazard Pointer and hazardpointer in parallel programming

Source: Internet
Author: User

Reclaim Hazard Pointer and hazardpointer in parallel programming

In the previous article, the RCU technology is used to implement Lock-free read/write threads. In languages without GC mechanisms, to implement the Lock-free algorithm, you will inevitably have to handle the issue of memory Reclaim by yourself.

Hazard Pointer is another algorithm used to solve this problem. It is not only simple, but also powerful. The data structure unrelated to the lock is well described in the Hazard pointer, And Wikipedia Hazard pointer is also clearly described, so I will not elaborate on it here.

For a simple implementation, refer to my github haz_ptr.c

Principle

The basic principle is that the read thread identifies the pointer. When the pointer (pointing to the memory) is to be released, the cache will be delayed until it is confirmed that there is no read thread to release it.

<Lock-Free Data Structures with Hazard Pointers>Description in:

Each reader thread owns a single-writer/multi-reader shared pointer called "hazard pointer. "When a reader thread assigns the address of a map to its hazard pointer, it is basically announcing to other threads (writers)," I am reading this map. you can replace it if you want, but don't change its contents and certainly keep your deleteing hands off it."

Key structures include:Hazard pointer,Thread Free list

Hazard pointer: When a read thread uses a pointer, a Hazard pointer is created to wrap the pointer. A Hazard pointer will be written by one thread and read by multiple threads.

Struct HazardPointer {void * real_ptr; // wrapped pointer... // different implementations have different members}; void func () {HazardPointer * hp = accquire (_ real_ptr );... // use _ real_ptr release (hp );}

Thread Free List: Each thread has a list that stores the pointer list to be released. This list only corresponds to the thread read/write

void defer_free(void *ptr) {        _free_list.push_back(ptr);    }

When a thread tries to release the pointer in the Free List, for example, pointerptrCheck the Hazard pointer used by all other threads and check whether the package exists.ptrIf not, it indicates that no read thread is usingptr, Can be safely releasedptr.

void gc() {        for(ptr in _free_list) {            conflict = false            for (hp in _all_hazard_pointers) {                if (hp->_real_ptr == ptr) {                    confilict = true                    break                }            }            if (!conflict)                delete ptr        }    }

The above is actuallyHazard Pointer.

Management of Hazard Pointer

Not mentioned in the above Code_all_hazard_pointersAndaccquireThis is the management problem of Hazard Pointer.

In the data structure unrelated to the Lock and Hazard Pointer, a Lock free linked List is created to represent the global Hazard Pointer List. Each Hazard Pointer has a member to identify whether it is available. This List stores the used Hazard Pointer set and the unused Hazard Pointer set. When all Hazard pointers are used, a new one will be allocated and added to this List. When the read thread does not use a Pointer, return the Hazard Pointer and directly set the available Member ID. Yesgc()Directly traverse the List.

It is very easy to implement a Lock free linked list and only implement header insertion. When Hazard Pointer identifies a Pointer, the Pointer is immediately identified. Therefore, this implementation directly supports dynamic threads and thread suspension.

There is also a Hazard Pointer implementation in the nbds project, which is relatively weaker. It sets its own Hazard Pointer pool for each thread. When the writing thread wants to release the Pointer, It accesses the Hazard Pointer pool of all other threads.

Typedef struct haz_local {// Free List pending_t * pending; // to be freed int pending_size; int pending_count; // Hazard Pointer pool, two types of haz_t static_haz [STATIC_HAZ_PER_THREAD]; haz_t ** dynamic; int dynamic_size; int dynamic_count;} _ attribute _ (aligned (CACHE_LINE_SIZE) haz_local_t; static haz_local_t haz_local _ [MAX_NUM_THREADS] = {};

Of course, each thread involveshaz_local_The allocation of indexes (IDS) is the same as that of read/write threads without locks using RCU technology. To support dynamic creation of threads, a thread ID reuse mechanism is required, which is much more complicated.

Appendix

Finally, some concepts in parallel programming are attached.

Lock Free & Wait Free

Often seeLock FreeAndWait FreeConcepts. These concepts are used to measure the parallel level of a system or code segment. For details about the parallel level, see parallel programming-concurrency level. In short, Wait Free is a more powerful level than Lock Free.

In my own understanding, for example, the Hazard Pointer linked list implemented in "Lock-independent data structure and Hazard Pointer" can be said to be Lock Free. Note that when inserting new elements into the chain table header, becauseCAS, There is always a busy loop, even if this feature existsLock Free, Although there is no lock, the execution of a thread is also affected by other threads.

Relatively speaking,Wait FreeThe execution of each thread is independent. For example, in the data structure unrelated to the lock and the Hazard pointerScanFunction."The execution time of each thread does not depend on the behavior of any other thread"

Lock-Free means that there is always a thread in the system that can continue to execute; while Wait-Free is a stronger condition, it means that all threads can proceed.

ABA Problems

In implementationLock FreeIn the process of algorithm, always useCASPrimitive, andCASIt will bringABAProblem.

During the CAS operation, CAS mainly asks "whether the value of V is still A" before changing the value of V. Therefore, after reading V for the first time and before performing the CAS operation on V, if you change the value from A to B and then back to A, the CAS-based algorithm will be chaotic. In this case, the CAS operation is successful. Such problems are called ABA problems.

Wiki Hazard Pointer mentioned a good example of ABA problem: in a Lock free stack implementation, the elements in the stack are[A, B, C],headPoint to the top of the stack.compare_and_swap(target=&head, newvalue=B, expected=A). However, in this operation, other threadsABAll are out of the stack and deletedB, AndAIn the stack, that is[A, C]. Then the previous thread'scompare_and_swapSuccessful.headPoint to a deletedB. Stackoverflow also has an example of Real-world examples for ABA in multithreading.

The common solution for this ABA problem produced by CAS is to use a variant DCAS of CAS. DCAS adds a referenced identifier for each V to indicate the number of modifications. For each V, if the reference is modified once, this counter is added with 1. Then, when the variable needs to be updated, both the value of the variable and the value of the counter are checked.

But some people have proposedDCASIt is not a silver bullet of ABA problem.

Address: http://codemacro.com/2015/05/03/hazard-pointer/
Written by Kevin Lynx posted athttp: // codemacro.com

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.