I am using a std::list in a multithreaded program. Elements are only added to the end of the list and only removed from the beginning of the list. There exists a writer lock to guarantee mutual exclusion for writes. Readers access the list without obtaining the lock. The readers maintain iterators which cannot be invalidated by erase() as I guarantee that elements are only erased if the readers have passed them. The only possible data race I can imagine is if an element is appended, and one of the readers accesses that element before the inserter has written the element itself.
With a single writer, appending (insert at the end) should be atomic as a single write is needed to insert the new element.
std::list apparently gives no guarantees whatsoever, can somebody confirm that above usage should work without data races. If not, is there an alternative (e.g. boost) which gives such a guarantee?
-
"std::list apparently gives no guarantees whatsoever" - you said it yourself. If it gives no guarantees, you can't rely on it only accessing the last node when you insert at the end (because it doesn't guarantee that). You certainly can't rely on appending being atomic (because it doesn't guarantee that either).Stack Exchange Broke The Law– Stack Exchange Broke The Law2015年02月04日 00:07:47 +00:00Commented Feb 4, 2015 at 0:07
-
thats why I am asking for alternatives. Also it might very well be that my use case is supported, the documentation just doesn't state it due to the sheer number of use cases.hlitz– hlitz2015年02月04日 01:49:14 +00:00Commented Feb 4, 2015 at 1:49
2 Answers 2
As you wrote, a race condition can happen:
The only possible data race I can imagine is if an element is appended, and one of the readers accesses that element before the inserter has written the element itself.
Also std::list is a doubly-linked list, so while removing the first element the second is accessed and while adding a new element the old last element is written to. So your iterators must be constant (no ++iter or --iter).
You may want to have a look at boost::lockfree::queue — it might be exactly what you are looking for.
1 Comment
I used boost::intrusive::list which solves the problem when disabling the size counter, which became inconsistent when simultaneously removing and inserting elements. Without this the boost list sets four pointers and nothing else when removing/inserting elements which is what I need.
Comments
Explore related questions
See similar questions with these tags.