How to force the const find to be called - c++

I'm coding with std::map in C++11.
I've read this link, which told me that the C++11 standard guarantees that const method access to containers is safe from different threads.
As my understanding, it means that std::map::size() is thread-safe, because this function is declared as size_type size() const noexcept;.
Now I want to call the function std::map::find thread-safely. For example, if (mp.find(xxx) != mp.end()) {}. However, there are two versions of find, one is const and the other is non-const:https://en.cppreference.com/w/cpp/container/map/find.
So how do I know which version of find is calling? How can I force the const-version find to be called in order to get a thread-safe code?
I knew there was a const version of std::map::cend(), will if (mp.find(xxx) != mp.cend()) {} work as expected?

You could have used std::as_const.
if(std::as_const(mp).find(xxx)==mp.end())
{
//do your thing
}

The general rule is that const is multiple-reader safe, and other operations are not.
But a number of exceptions are carved out. Basically, the non-const operations returning iterators or references to existing objects (no object is created) are also considered "reader" operations, and are multiple-reader safe. Using the non-const_iterators they return to modify the underlying data often has issues, but in many containers such modifications only cause contention if done on the same element that another operation is accessing.
So
if (map.find(foo) == map.end())
is safe to use with other operations that only read from the map object.
There are still good reasons to call the const operations. In c++17 there is std::as_const, permitting
if (std::as_const(map).find(foo) == map.cend())
which only calls const methods on map. You can write your own as_const easily:
template<class T>
std::add_const_t<T>& as_const( T& t ) { return t; }
(in c++11 you'll need to expand add_const_t). The std version adds
template<class T>
void as_const( T const&& t ) = delete;
to block some relatively pathological cases.
...
When thinking about thread safety, realize that it is a relational property. Two operations are relatively thread safe.
In the case of std containers, you have to think about how the operation reads or writes the container itself, which elements it reads or writes. While the standard is more technical, that will give you an intuitive understanding of what is allowed.
Methods that only read the container and return iterators or references to elements are sometimes non-const, but they themselves only read the container.
Operations that mutate or read elements are often only exclusive with other operations that mutate that element. In a vector, you are free to v[0] = 77; while another thread reads v[7] with no synchronization (outside of vector<bool>). But the moment you .push_back with insufficient capacity, you need to be synchronized with every other read.
This can be counter intuitive. Be careful, and read the documentation, if you are doing synchonization free access to a container. The intuition is only a first step.

If mp is const then find will be the const version. However calling the non-const version is no different in terms of thread safety than calling the const version, the difference comes if you actually use the returned iterator to make modifications to the held value (if you read the answer you linked carefully it contains this distinction).
Note that only calling multiple const methods is thread safe, calling a non-const method from another thread at the same time is not thread safe.

Related

C++11 / C++03 and std::vector thread safety

I am reading about thread safety of various stl containers from this link
Now I came across this point which states for C++11 only
Different elements in the same container can be modified concurrently
by different threads, except for the elements of std::vector<bool>
(for example, a vector of std::future objects can be receiving values
from multiple threads)
Does this mean if I have a method such as this which is being used by multiple
threads simultaneously (notice the method does not have any locks)
void ChangeValue(int index , int value)
{
someVector[index] = value;
}
Is the above method safe. My understanding is that it is safe for C++11 only.
However when I look at the other statement mentioned in the link
All const member functions can be called concurrently by different
threads on the same container. In addition, the member functions
begin(), end(), rbegin(), rend(), front(), back(), data(), find(),
lower_bound(), upper_bound(), equal_range(), at(), and, except in
associative containers, operator[], behave as const for the purposes
of thread safety (that is, they can also be called concurrently by
different threads on the same container). More generally, the C++
standard library functions do not modify objects unless those objects
are accessible, directly or indirectly, via the function's non-const
arguments, including the this pointer.
I come to the conclusion that in C++03 the above method can be safely used as well.
Kindly let me know if my understanding is correct.
It is meaningless to ask whether something is thread-safe under the C++03 standard - C++03 and earlier didn't have any concept of threads or thread safety.
ChangeValue is data race-free (as defined by C++11 and later) as long as no two threads pass the same argument for index, or else calls passing the same argument are synchronized with each other by some means external to the function.

std::map thread-safety

Is reference to object in std::map is thread safe?
std::map< std::string, Object > _objects;
map can be changed from many threads and this access is synchronized, but reference to value (Object &) accessable just from 1 instance and thread. is write operations with Object & is safe if another thread will add items to map? will it reallocate?
The C++11 standard guarantees that const method access to containers is safe from different threads (ie, both use const methods).
In addition, [container.requirements.dataraces] states
implementations are required to avoid data races when the contents of
the contained object in different elements in the same sequence,
excepting vector<bool>
In other words, except for vector<bool> modifying distinct contents is not a data race.
Now, if one thread invalidates an iterator used by another thread, clearly this is a data race (and results in undefined behavior). If one thread does non-const access to a container, and another does const access, that is a data race (and undefined behavior). (Note: a number of functions are "considered const" for the purpose of multithreading, including begin, end and other functions (and methods) that are non-const simply because they return non-const iterators. [] is included in this set of pseudo-const for thread safety reasons, except for map and unordered_set etc -- 23.2.2.1).
However, it appears that if you have a reference to an element within the container, and engage in operations that do not invalidate that reference in another thread, and never write to that element in another thread, you can safely read from that reference. Similarly, if other threads never even read from the element, then writing to that element shouldn't result in undefined behavior.
For standards references, 17.6.5.9.5 seems to guarantee that functions from the standard library won't run away and read/write elements needlessly.
So the short answer: you are safe, so long as the other thread doesn't directly mess with that particular entry in the map.
Elements in a map are stable, they do not get moved or invalidated unless the element is erased from the map. If only one thread is writing to a given object, and changes to the map itself are correctly synchronized, then I believe it will be safe. I'm sure it's safe in practice, and I think it's safe in theory too.
The standard guarantees that distinct elements can be modified by different threads, in [container.requirements.dataraces]
Notwithstanding (17.6.5.9), implementations are required to avoid data races when the contents of the contained object in different elements in the same sequence, excepting vector<bool>, are modified concurrently.
This only allows you to modify the elements, not to insert new elements into the map while modifying elements. For some containers, such as std::vector, modifying the vector itself might also modify elements by reallocating and moving them, but [associative.reqmts]/9 ensures std::map won't invalidate existing elements.
Since no member function of std::map is required to access the second member of its elements (i.e. the mapped_type) I think [res.on.data.races]/5 says no other thread will conflict with writes to that member when modifying the map. (Thanks to Yakk for that final piece of the puzzle)

Do all STL containers return their elements by reference?

I am learning STL these days and I was wondering if STL containers return by reference?
e.g:
vector.first();
map[key];
*vector.begin();
Or any possible return that ends with element (or value type) of container
e.g:
std::vector<int> elements;
elements.push_back(20);
elements[0]=60; // this will also change the value
elements.front() = 23; // even the functions also behave same way like subscript operator
is this the case with all containers? or there are some points to consider which I didn't show?
Returning the added element, or the container in container member functions is not possible in a safe way. STL containers mostly provide the "strong guarantee". Returning the manipulated element or the container would make it impossible to provide the strong guarantee (it would only provide the "basic guarantee"). An explanation of these terms is provided at boost's website on Exception-Safety in Generic Components. See below from Boost's website.
The basic guarantee: that the invariants of the component are preserved, and no resources are leaked.
The strong guarantee: that the operation has either completed successfully or thrown an exception, leaving the program state exactly as it was before the operation started.
The no-throw guarantee: that the operation will not throw an exception.
Back to the topic: Per this previous SO answer, the reason behind this is, that returning something could possibly invoke an copy-constructor, which may throw an exception. But the function already exited, so it fulfilled its main task successfully, but still threw an exception, which is a violation of the strong guarantee. You maybe think: "Well then lets return by reference!", while this sounds like a good solution, its not perfectly safe either. Consider following example:
MyClass bar = myvector.push_back(functionReturningMyClass()); // imagine push_back returns MyClass&
Still, if the copy-assignment operator throws, we don't know if push_back succeeded or not, thus indirectly violating the strong-guarantee. Even though this is not a direct violation. Of course using MyClass& bar = //... instead would fix this issue, but it would be quite inconvenient, that a container might get into an indeterminate state, just because someone forgot a &.
A quite similar reasoning is behind the fact that std::stack::pop() does not return the popped value. Instead top() returns the topmost value in a safe way. after calling top, even when a copy-constructor, or a copy-assignment constructor throws, you still know that the stack is unchanged.
Yes the overloaded [] operator for stl containers return a reference. So in your examples above the values in m and elements will be altered.
From http://www.cplusplus.com/reference/stl/vector/operator%5B%5D/ :
The definition or operator[] for vector is:
reference operator[] ( size_type n );
const_reference operator[] ( size_type n ) const;
Where 'Member types reference and const_reference are the reference types to the elements of the vector container (generally defined as T& and const T& respectively in most storage allocation models).'
Edit: Be aware that not all stl containers have an overloaded [] operator. Those that don't are: list, multimap, multiset, priority_queue, queue, set and stack.
All the types of containers (sequence, associative) are designed to provide a consistent interface (where possible). It makes learning them relatively easy and using them even easier (as long as you've learnt them properly! ;) )
So for example, operator[] for all containers will return a reference to the entity indexed (in the case of the associate containers, it will be created first). For the sequence containers this raises an interesting point about bounds checking - but that's a different story. Similarly, if you take any other common operation (insert etc.) will have a similar interface. Your favourite reference will typically provide all the information you need.
std::vector<bool> is allowed to return something else than a reference to bool (assuming you really mean the standard library, not the SGI STL). But it is also generally seen as a mistake that does not deserve to be called a container.

custom allocator using move for vector of thread

I'm currently learning about concurrency in C++ and came across using a vector of threads, which I believe will be possible in C++0x. However, my current compiler doesn't appear to have an implementation of move-aware containers and so I get errors generated because std::thread::thread(const std::thread&) is deleted, ie I can only use the move constructor/move assignment with std::thread.
Am I correct in thinking I could circumvent this issue by writing a custom allocator using
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
rather than
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
? Or some other variation on this theme (possibly using an overload of MyAllocator::construct).
NB: This is mainly intended to be a short-term educational exercise and well enough performing work around to play around with threads in containers. I'd only be using MyAllocator in this context. However, please also point me at any libraries that may have this implemented so I can have a poke around the source.
If your compiler doesn't provide a move-aware std::vector then you'll have to write your own specialization of std::vector<std::thread> rather than just provide a custom allocator. The whole C++03 vector interface relies on copying: push_back() copies elements in; resize() initializes the empty elements with a copy of the element passed as the second parameter (even if that is the default value of T()); resize(), reserve(), insert(), erase() and push_back() will copy elements if the vector needs reallocating, or elements otherwise need moving around, and so forth.
This is such a common problem that I've included such a specialization with my (commercial) just::thread implementation of std::thread.
The easiest way to circumvent the problem would be to allocate the threads on the heap and manipulate pointers to them.
Check the Boost Pointer Container library: boost::ptr_vector<std::thread> seems to me what you are looking for.
The requirement that std containers only take copyable objects has more to do with the C++03 container interfaces than it does with the allocator implementation.
For example
vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);
The standard assures us a==b is true. However, if T were not copyable, then in the best case a=b will not compile, in the worst a=b is undefined. Furthermore,
a.push_back(T());
may cause a to allocate new space, and under the hood there are copies made to the new underlying storage from the old.
Furthermore, there is nothing in the C++03 standard that says an implementation actually has to call allocator.construct, and in fact many (gcc for example) do not.
The C++0x standard adds new member functions to the container interface for moveable types, and clarifies how things like operator= behave in their presence.
See www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf

What operations are thread-safe on std::map?

Suppose I have:
stl::map<std::string, Foo> myMap;
is the following function thread safe?
myMap["xyz"] ?
I.e. I want to have this giant read-only map that is shared among many threads; but I don't know if even searching it is thread safe.
Everything is written to once first.
Then after that, multiple threads read from it.
I'm trying to avoid locks to make this as faast as possible. (yaya possible premature optimization I know)
C++11 requires that all member functions declared as const are thread-safe for multiple readers.
Calling myMap["xyz"] is not thread-safe, as std::map::operator[] isn't declared as const.
Calling myMap.at("xyz") is thread-safe though, as std::map::at is declared as const.
In theory no STL containers are threadsafe. In practice reading is safe if the container is not being concurrently modified. ie the standard makes no specifications about threads. The next version of the standard will and IIUC it will then guarantee safe readonly behaviour.
If you are really concerned, use a sorted array with binary search.
At least in Microsoft's implementation, reading from containers is thread-safe (reference).
However, std::map::operator[] can modify data and is not declared const. You should instead use std::map::find, which is const, to get a const_iterator and dereference it.
Theoretically, read-only data structures and functions do not require any locks for thread-safety. It is inherently thread-safe. There are no data races on concurrent memory reads. However, you must guarantee safe initializations by only a single thread.
As Max S. pointed out, mostly implementation of reading an element in map like myMap["xyz"] would have no write operations. If so, then it is safe. But, once again, you must guarantee there is no thread which modifies the structure except the initialization phase.
STL collections aren't threadsafe, but it's fairly simple to add thread safety to one.
Your best bet is create a threadsafe wrapper around the collection in question.
This is an old question, but as all existing answers -and in particular the accepted one- are incorrect, I am adding another one (sorry, not enough rep for comments).
Because the OP explicitly mentions a read-only access (_"giant read-only map"), the [] operator should actually not be used since it can result in an insert. The at or find methods are suitable alternatives.
Some non-const functions are considered const in the context of thread-safety. at and find are such pseudo-const functions (this is explained very nicely in another question. More details are available from cppreference.com as well under the "thread-safety" section. And finally and see C++11 standard 23.2.2.1 for the official list).
As long as only const operations are used on the container the execution is thread-safe. As you initialize the huge map once (and do not modify it afterwards) before accessing it read-only from other threads, you are safe!