Lockfree Insert Operation
Now we need to deal with actual inserts somehow. The best we can afford (in terms of scalability) is a lockfree algorithm. The algorithm for ordered singly-linked list insertion is well-known, and takes 1 CAS operation in the best (and average) case (note that the function takes as parameters hints for previous and next nodes, which are discovered during preceding searching) (C++0x synchronization primitives are used):
/** ordered singly-linked list insert
* @prev hint for the previous element
* discovered by a find operation
* it's key is smaller than inserting key
* @next hint for the next element
* discovered by a find operation
* it's key is larger than inserting key
* @node the node to insert
* @return true if inserted
* false if the key is already present in the list
*/
bool slist_insert(node_t* prev, node_t* next, node_t* node)
{
for (;;)
{
// try to insert the node with CAS operation
node->next.store(next, memory_order_relaxed);
if (prev->next.compare_exchange_strong(next, node, memory_order_release))
// if the CAS succeeded, the node is inserted
return true;
// otherwise, something has changed,
// and we need to find a new location for the insertion
// (i.e. update 'prev' and 'next')
for (;;)
{
// re-compare the values
int cmp = traits_t::compare(node->item, next->item);
if (cmp > 0)
{
// new 'next' node's key is smaller than the inserting key
// so remember it as a 'prev', and repeat the comparation
prev = next;
next = prev->next.load(memory_order_consume);
if (next == 0)
break;
continue;
}
else if (cmp == 0)
{
// the key is present in the list
return false;
}
else /* (cmp < 0) */
{
// new 'next' node's key is still larger than the inserting key
// so just retry the CAS
break;
}
}
}
}
Move on to Node Count Maintenance