Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::list thread_safety

  1. I have a list where one thread just does push_back and other thread occasionally loop through the list and prints all the elements. Do I need a lock in this case?
  2. I have pointers to the elements in some other object. Is it safe to have? I know that vector will move all the objects when it needs more space so pointers will be invalidated.

    mylist.push_back(MyObj(1));
    if(someCond)
    {
    _myLastObj = &mylist.back();
    }

_myLastObj is of type MyObj*

If I had used a vector, the object would have been moved to a different location and the pointer would be pointing to garbage. Is it safe with a list?

like image 565
balki Avatar asked Dec 02 '22 22:12

balki


1 Answers

  1. yes, you need a lock (some form of synchronization).
  2. pointers to elements of a std::list are invalidated only if that same element is removed from the list. Since your code never removes anything from the list, your pointers are safe.

For a concrete reason why you need the lock, consider for example that list::push_back is permitted to do the following, in this order:

  1. allocate a new node,
  2. set the "next" pointer of the tail of the list to the new node,
  3. set the "next" pointer of the new node to null (or some other end-of-list-marker),
  4. set the "previous" pointer of the new node to the previous tail,
  5. set the list's own pointer-to-tail to the new node.

If your reader thread comes in between 2 and 3, then it will go from the previous tail, to the new node, then try to follow an uninitialized pointer. Boom.

In general though, you need synchronization because it's the only way to guarantee that changes made in the writer thread are published to the reader thread in any kind of sensible order (or at all).

Your code should be correct if you imagine that different threads run on different planets, each with its own copy of your program's memory, and transmit changes to each other (a) when you use a synchronization object (or atomic variable in C++11), plus (b) when you don't use a synchronization object but transmitting some particular partial change will break your code (such as one half of a two-word object or in this case one of two pointer writes that you need to occur in a particular order). Sometimes this model is more conservative than strictly necessary, and results in slower code. But a less conservative model relies on implementation-specific details of the threading system and memory model.

like image 155
Steve Jessop Avatar answered Dec 07 '22 22:12

Steve Jessop