hovnatan
hovnatan

Reputation: 1385

c++11 std::hash function object classes thread safety

In c++11 are the hash function class objects declared in <functional> thread safe? E.g., is it safe to call this function from multiple threads?

size_t hash1(const std::string& s) {
    std::hash<std::string> str_hash;
    return str_hash(s); 
}

or, if one has a global object std::hash<std::string> str_hash_global;, then is it safe to call this second function from multiple threads?

size_t hash2(const std::string& s) {
    return str_hash_global(s); 
}

Upvotes: 7

Views: 1101

Answers (2)

Jonathan Wakely
Jonathan Wakely

Reputation: 171383

The same "thread-safety" rules apply here as for all std::lib types.

The first version is guaranteed to be thread-safe because there are no variables shared between threads.

The second one is guaranteed to not have any data races if the operator() that gets called is const. It is unspecified whether the implementation provides a (potentially non-thread-safe) non-const overload of hash<T>::operator() in addition to the (required) const one. If your global_str_hash is const, or you cast it to const before using it, then you guarantee the const operator() will be used.

There is no reason to do the second version, it's just silly, but in practice it should be safe because no standard library implementation is likely to provide a racy non-const overload of hash::operator(), they will only provide a const overload, which must be thread-safe.

Upvotes: 3

Kerrek SB
Kerrek SB

Reputation: 477368

The standard library promises that if you only call const-qualified member functions on a standard library object, the standard library code does not cause a data race (cf. [res.on.data.races]).

The standard template std::hash, as well as all its permissible specializations, as well as any user-provided functor that meets the Hash requirements ([hash.requirements]) must have a const-qualified call operator due to the requirements, and thus using the library-provided std::hash specializations should not cause a race. Moreover, due to [namespace.std], program-provided specializations must meet the same requirements.

Finally, I imagine that you would usually use the race-freeness guarantees by recursively appealing to const calls: If you multiple threads concurrently look up values in a map, they have to use the map's const interface to invoke the above library rule, but then the map only gets to use a constant value of the hasher (or a private copy), and so it can itself only perform race-free hash computations. Whether a racy non-const call operator exists is immeterial at that point.

Upvotes: 6

Related Questions