Skeleton of the Linked List
1 | template <typename T> |
The implementation of push_back
1 | void SList<T>::push_back(T& data) { |
Drawback
Let’s consider the situation of batch insertion, this implementation will do harm to our efficiency becaue of the cost on lock(which requires the contet switch)
Yet a better way to insert item to linked list
1 | void SList<T>::push_back(T* data, int count) { |
Optimization for Searching Item
Considering when some process are doing iteration task, while the others is inserting or deleting.Some we need to classify these two situations, change or not change.
1 | template <typename T> |
Search Code
1 | bool SList<T>::find(const T& value){ |
Concurrent Insertion
To support current insertion, we need add the lock for each Node, so the new framework should be:
For the linked list, we assign a read-write lock. For each node in the linked list, we assign a mutex node.
1 | template <typename T> |
Add the read lock for searching, while add the mutex lock for the modified node.
1 | void SList<T>::insert_after(T& previous,T& value) { |
Is lock necessary?
First let us introduce the CMPXCHG instruction on Intel chips, it is an atomic instruction but composed of serveral simple function. If we translate its function into C language:
1 | int compare_and_swap ( int *memory_location, int expected_value, int new_value) |
This is short for compare and swap instruction. When you reach this, you must be curious about what the hell this is doing for?The answer is to design a lock free data structure.
Design a lock-free concurrent data structure
First let’s walk through the layout of to-be-designed data structure.
1 | template <typename T> |
The implementation of push should use the CAS instruction. Let us paraphrase the __sync_bool_compare_and_swap(&top, n->next, n)
, which means that in each time we move the n to the next node, we need to check whether n->next == top
, true means no other thread change the value of top, we can let the top point to the current top(n). Otherwise, we should redo the n->next =top
to update the new top.
1 | void Stack<T>::push(const T& data){ |
Here we need to pay attention that the execution of __sync_bool_compare_and_swap is atomic for CPU, this is the prerequisite of our design.
For the same reason, we implement the pop function. In case of the system crush when we do the &top since top is NULL, we need to add the non_NULL check through the code.s
1 | T Stack<T>::pop( ) |