Home DEVELOPER Deferred reclamation in C++26: read-copy updates and dangerous pointers

Deferred reclamation in C++26: read-copy updates and dangerous pointers

0


A common problem with consistency is the so-called ABA problem. This means that you read a variable A twice always returning the same value A. Therefore, you come to the conclusion that nothing has changed in between. But you forgot b.

Advertisement





Rainer Grimm has been working as a software architect, team and training manager for many years. He likes to write articles on the programming languages ​​C++, Python and Haskell, but also likes to speak at expert conferences. On his blog Modern C++, he deals in depth with his passion C++.



The following scenario presents the problem.

The scenario looks like you sit in your car and wait for the traffic light to turn green. In our case, Green stands for B and Red for A. What’s next?

Javaland 2025: Secure Early Bird Tickets Now
  1. You look at the traffic lights and it’s red (A).
  2. Because it’s boring, you look at the news on your smartphone and forget the time.
  3. You see the traffic light again. Damn it’s still red(a).

Between the two checks the traffic light turns green (B). So there were two red phases, although it seemed just one.

What about threads (processes)? Now again very formally.

  1. Thread 1 reads a variable var With value A.
  2. Thread 1 is interrupted and thread 2 is done.
  3. thread 2 changes variable var A to B.
  4. Thread 1 starts with execution and checks the value of the variable varSince the value of the variable var The same remains, thread 1 continues its work,

Often you can ignore ABA.

In the following code, the function multiplies fetch_mult (1) A std::atomic&that mult is shared.

// fetch_mult.cpp

#include 
#include 

template 
T fetch_mult(std::atomic& shared, T mult){                          // 1
  T oldValue = shared.load();                                          // 2
  while (!shared.compare_exchange_strong(oldValue, oldValue * mult));  // 3
  return oldValue;
}

int main(){
  std::atomic myInt{5};
  std::cout << myInt << '\n';          
  fetch_mult(myInt,5);
  std::cout << myInt << '\n';         
}

shared.compare_exchange_strong(expected, desired)(3) Have the following behavior:

  • if comparison false result, will expected But shared set.
  • If nuclear comparison true result, will shared in the same nuclear operation expected set.

The most important observation is that there is a small time window between reading the old value T oldValue = shared.load (2) and comparison with the new value (3). Therefore, another thread can step in and oldValue From oldValue To anotherValue and again oldValue Change. anotherValue B is in ABA.

I would like to describe ABA based on a lock-free data structure.

I use a lock-free stack that is implemented as a chained list. The stack supports only two operations.

  1. Pops the top object and returns a pointer.
  2. Push the specified object onto the stack.

I would like to describe the pop operation in pseudocode to give you an idea of ​​the ABA problem. The pop operation performs the following steps in a loop until it succeeds.

  • Get the head knot: Head
  • Get the following nodes: headnext
  • Make headnext When the new head Head still the head of the stack

Here are the first two knots of the stack:

Stack: TOP -> head -> headNext -> ...

Let’s start with the following stack:

Stack: TOP -> A -> B -> C

Thread 1 is active and wants to remove the stack head.

Before thread 1 finishes the pop algorithm, thread 2 is active.

Stack: TOP -> B -> C

  • Thread 2 removed B and deleted B

Stack: TOP -> C

  • Thread 2 pushes one back

Stack: TOP -> A -> C

Thread 1 is new to check if A == headda a == headbecomes headNextSo B, for the new head. But B has already been removed. Therefore, the program has an undefined behavior.

There is some help for the ABA problem.

The conceptual problem of ABA is relatively easy to understand. like a knot B == headNext Although another knot was removed, A == headReferred to it. The solution to our problem is to prevent the knot from being removed prematurely. Here are some solutions.

  • reference to a marked state

You can add a day to indicate how many times the knot has been successfully changed. However, the “compare and exchange” method fails at some point, although the review (/code) is correct (/code).

The next three techniques are based on the idea of ​​deferred recapture.

Garbage collection guarantees that variables will only be deleted when they are no longer needed. This sounds promising, but there is one big disadvantage. Most garbage collectors are not lock-free. So, you have a lock-free data structure, but the overall system is not lock-free.

From Wikipedia: Danger signs:

In a dangerous-pointer system, each thread leads a list of dangerous pointers that indicate which nodes the thread accesses. (This “list” may be limited to only one or two elements in many systems.) Lumps on the dangerous pointer list must not be changed or released by another thread. …If a thread wants to remove a knot, it relies on a list of knots that “must be released later”, but only releases the node’s memory if there are no other threads in the threat list. Is. A dedicated garbage collection thread can perform this manual garbage collection (if the list “release later” is shared by all threads); Alternatively, clearing the “shared” list can be done by each task thread as part of an operation such as “pop”.

RCU stands for READ Cmake a copy of YouPDate, a synchronization technique developed by Paul McKechnie and used in the Linux kernel since 2002 for nearly write-protected data structures.

The idea is quite simple and follows the acronym. To change data, make a copy of the data and change this copy. In contrast, all readers work with the original data. If there is no reader, the data structure can be replaced by copying without hesitation.

In my next article I will implement a lock-free stack with deferred reclamation.


(rme)

Product Worker: Combination of OKR and Scrum wisely

NO COMMENTS

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Exit mobile version