mardi 28 juillet 2015

May C++11 standard libraries use internal static const variables without syncronization?

I'm trying to design a thread-safety specification for parts of our existing C++ library. I thought it would be a good idea to look at the guarantees given by the standard library, and stumbled upon §17.6.5.9[res.on.data.races] (from the C++11 standard), which is puzzling me:

  1. A C ++ standard library function shall not directly or indirectly access objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function's arguments, including this.
  2. A C ++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function's non-const arguments, including this.
  3. [ Note: This means, for example, that implementations can't use a static object for internal purposes without synchronization because it could cause a data race even in programs that do not explicitly share objects between threads. — end note ]

(I've included 3. and 4. here because 4. clarifies the preceeding paragraphs in that an object is not considered accessible if I use syncronization to coordinate the accesses. But I am mostly concerned with 2.)

If I apply that to my own library, I cannot have a function like this:

double area_of_circle(double radius)
{
  static const double pi = acos(-1.0); // syncronized
  return pi*radius*radius; // unsyncronized access to pi
}

The initialization of pi is syncronized as per §6.7[stmt.dcl]/4, but reading pi in the return statement could happen concurrently from multiple threads. This cannot introduce a race, since the unsyncronized accesses are only reads, yet paragraph 2. above seems to forbid this.

Note that there is also paragraph 7:

  1. Implementations may share their own internal objects between threads if the objects are not visible to users and are protected against data races.

This just seems to reiterate 2. and 3. Unless "protected against data races" means something less strict than "not accessible by threads other than the current thread". But I'm not really sure what is actually meant here.

So my questions are:

  1. Am I interpreting the legalese of the standard correctly? If I want to offer the same guarantees as the standard library with regard to threading in my own library, would I need to use locking when accessing pi in the example above?
  2. If yes, is this intended, or was this an oversight?
  3. If this was inteded, what are the reasons?

Aucun commentaire:

Enregistrer un commentaire