18

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)

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
anon
  • 41,035
  • 53
  • 197
  • 293

6 Answers6

17

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.

dalle
  • 18,057
  • 5
  • 57
  • 81
12

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.

tony
  • 3,737
  • 1
  • 17
  • 18
6

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.

Max Shawabkeh
  • 37,799
  • 10
  • 82
  • 91
  • in order for there to be anything in a container, it needs to be written to. Hence the thread safety concern... – Mitch Wheat Jan 31 '10 at 04:51
  • 1
    The questions specifies that we are looking at a read-only map. I assume this means it is filled completely in one thread before being read from multiple threads. – Max Shawabkeh Jan 31 '10 at 05:24
4

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.

minjang
  • 8,860
  • 9
  • 42
  • 61
1

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.

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
0

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!

geonanorch
  • 31
  • 3
  • `map::operator[]` can insert new elements in the map, so it is not thread-safe, https://en.cppreference.com/w/cpp/container/map/operator_at – Fedor May 29 '22 at 16:47
  • @Fedor I agree and I will update my answer to remove the ambiguity: the OP explicitly mentioned a const access (_"giant **read-only** map"_), and in that context I see the `[]` operator as equivalent to the `at` method, which is considered const. – geonanorch May 31 '22 at 06:22
  • update of previos comment: @Fedor thank you, I agree and I will update my answer to remove the ambiguity: the OP explicitly mentioned a const access (_"giant **read-only** map"_), but I implicitly used that context to downgrade the `[]` operation to an `at` method call, which is thread-safe. In fact, considering the OP's intention `at` or `find` should be used instead of `[]` to ensure that the map is not modified. – geonanorch May 31 '22 at 06:34