Modify the lazy list using epoch based reclamation (EBR, a method of domain specific reclamation)

Posted by jonmkim on Sat, 11 Dec 2021 07:53:27 +0100

As mentioned earlier, the biggest hidden danger of lazy list is logical deletion, but there is no physical deletion problem. Therefore, EBR first solve d this problem to him.

I EBR modification

int parse_delete(intset_l_t *set, val_t val) {
    node_l_t *pred, *curr;
    int result, validated, isVal;
    while(1) {
        //Init
        pred = set->head;
        curr = get_unmarked_ref(pred->next);
        //Unmark and lock each node
        while (curr->val < val) {
            pred = curr;
            curr = get_unmarked_ref(curr->next);
        }
        LOCK(&pred->lock);
        LOCK(&curr->lock);
/*
* Mark Phase: 
* Start from the root set to find all memory block references, and then mark the referenced memory block (mark)
*/
        //check its validated and curr->val whether equals val
        validated = parse_validate(pred, curr);
        isVal = val == curr->val;
        result = validated && isVal;
        //only meeting at same time, make pred->next = newnode
        if (result) {
            curr->next = get_marked_ref(curr->next);
            pred->next = get_unmarked_ref(curr->next);
        }
        //UNLOCK curr and pred
        UNLOCK(&curr->lock);
        UNLOCK(&pred->lock);
/*
* Sweep Phase:
* All memory blocks that are not marked are considered garbage and can be recycled
*/
        //find memory blocks that are not marked, setting a mark bit to 1
        result = result && parse_find(curr,isVal);
        //wait until pred and curr meet the validate conditions, exit this loop
        if(validated){
            //free the element
            free(curr);
            return result;
        }
            
    }
}

II Performance comparison before and after

original:

unsafe:

In the original version, 2 threads complete from 1 to 10 readings, while in the unsafe version, 5 threads get 50 jobs, and the terminal display time is almost the same.

Compared with the past, the existing performance has the following advantages.

Firstly, the efficiency of the program is greatly improved, and the advantages of multi-core CPU are really brought into play to make full use of CPU. Then, it can prevent blocking and promote the establishment of the whole program model. It is very suitable for multiple identical threads to process the same resource. Moreover, synchronous collection is much faster and more flexible than before.

III Constructing artificial environment reflects insecurity

As mentioned earlier, after the change, it is an unsafe version, so where is the unsafe version?
When counting, single thread may be correct, but multi-threaded error
Because a multithreaded operation will only see its current thread, the order of changing variables is not fixed.
Here we use java multithreading to show the results

public class jthread {
    public static void main(String[] args) {
        //Test 3 people in multithread condition
        WebTickets w = new WebTickets();
        
        Thread t = new Thread(w,"Alan");
        t.start();
        
        Thread t1 = new Thread(w,"Mike");
        t1.start();
        
        Thread t2 = new Thread(w,"Jay");
        t2.start();
    }

}

class WebTickets extends Thread{
    private int ticketNums = 99;
    // from ticket = 99 to 0, 3 people buy these tickets
    public void run(){
        while(true) {
            //when ticket<=0, stop
            if(ticketNums<=0) {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //sout the consquence
            System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
        }
    }
}


As shown in the figure, the ticket grabbing applet written in java can't stop and grab tickets below 0.

Therefore, the implementation of synchronization mechanism needs to pay attention to the following points: high security, low performance, multi-threaded use. High performance, low security, for single thread.

  1. Do not synchronize all methods of the thread safe class, only those that change the shared resources.
class WebTickets implements Runnable{
    //create static key
    static Object str = "str"; //Random value
    private int ticketNums = 99;
    // from ticket = 99 to 0, 3 people buy these tickets

    @Override
    public void run(){
        while(true) {
            //when ticket<=0, stop
            synchronized(str){ //use lock
                if(ticketNums<=0) {
                    break;
                }
                try {
                    Thread.sleep(200);//rest 0.2 seconds
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
            }
        }
    }
}

2. If the variable class has two running environments, in the threaded environment and multithreaded environment, the variable class should have two versions: thread safe version and thread unsafe Version (without synchronization method and synchronization block). In a single threaded environment, the thread unsafe version is used to ensure performance, and the thread safe version is used for multithreading.

Topics: C++ data structure linked list list Memory Leak