Title
Incomplete thread specifications
Status
c++17
Section
6.9.2 [intro.multithread]
Submitter
Dinka Ranns

Created on 2014-11-17.00:00:00 last changed 36 months ago

Messages

Date: 2016-02-15.00:00:00

Notes from the February, 2016 meeting:

SG1 is included to introduce the “strongly happens before” relation from P0250, although possibly in a differnt way. It seems to be needed to fix all sorts of wording that's currently imperfect because it doesn't work in the presence of memory_order_consume.

Date: 2015-10-15.00:00:00

Notes from the October, 2015 meeting:

A paper is required to address these issues fully. A lot of the existing text talks about sequencing when it should refer to “the transitive subset of happens before,” which could be, but is not currently, defined. “Happens before” would do if we didn't have memory_order_consume. The SG1 consensus on what should be said includes the following:

  • main should have a proper thread id, which should not be the default-constructed thread id.

  • atexit should use flows of control with valid thread ids.

  • For non-thread-local objects, we should guarantee only happens-before relationships for ordered initializations, slightly strengthened if we have memory_order_consume.

  • Thread-locals should be initialized by the thread that they correspond to (which simplifies initializations that rely on each other).

  • A C++ program should be allowed to start a std::thread even if the user never starts one.

  • The thread-id for global static initialization is unspecified, but it is not the default-constructed thread.

Date: 2017-02-15.00:00:00

[Adopted at the February/March, 2017 meeting as document P0250R3.]

Given the example:

    auto id1 = std::this_thread::get_id();
    thread_local auto id2 = std::this_thread::get_id();
    int main()
    {

      auto id3 = std::this_thread::get_id();
      auto id4 = std::this_thread::get_id();
      std::cout << id1 << std::endl << id2 << std::endl << id3 <<
          std::endl << id4 << std::endl;
    }
  1. What is the thread of execution that initializes id1? Is it the same as, different from, or unspecified in relation to id3?

  2. I believe this is unspecified by omission. (I can find no wording in the standard saying otherwise.) It looks like the standard attempts to require that these happen in the same thread, but fails to do so. We say that in a program that does not start a thread, all ordered dynamic initializations are sequenced, which implies they happen in the same thread — because “sequenced before” is an intra-thread notion — but we do not say that these initializations are sequenced before entering main (we just say they may be “done before” entering main). This seems like a defect to me.

  3. What is the thread of execution that initializes id2? Is it the same as, different from, or unspecified in relation to id1 and id3?

  4. This also seems to be unspecified; this seems like a defect. We say in 6.9.3.2 [basic.start.static] paragraph 5:

    It is implementation-defined whether the dynamic initialization of a non-local variable with static or thread storage duration is done before the first statement of the initial function of the thread. If the initialization is deferred to some point in time after the first statement of the initial function of the thread, it shall occur before the first odr-use (6.3 [basic.def.odr]) of any variable with thread storage duration defined in the same translation unit as the variable to be initialized.

    but “done before” and “occurs before” are meaningless noise here. I think what is intended is that these are a “sequenced before” relation for initialization of thread storage duration entities (implying initialization in the same thread) and “happens before” for initialization of static storage duration entities (implying initialization in some thread but visible to this thread).

  5. Am i guaranteed to have only one copy of id2, or could there be more?

  6. You are guaranteed to have one per thread, per 6.7.5.3 [basic.stc.thread] paragraph 1.

    I cannot find any explicit guarantee that the implementation will not create additional threads behind your back, so there appears to be no guarantee that you have only one id2 variable. That may be a defect.

I'm also concerned by 6.9.3.2 [basic.start.static] paragraph 2:

...Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit...

This is obviously wrong if a translation unit contains both static and thread storage duration variables.

History
Date User Action Args
2018-02-27 00:00:00adminsetmessages: + msg6155
2018-02-27 00:00:00adminsetstatus: concurrency -> c++17
2015-11-10 00:00:00adminsetmessages: + msg5689
2014-11-17 00:00:00admincreate