Title
Data races during construction
Status
cd2
Section
11.9.5 [class.cdtor]
Submitter
Jeffrey Yasskin

Created on 2008-05-03.00:00:00 last changed 171 months ago

Messages

Date: 2010-03-15.00:00:00

[Voted into WP at March, 2010 meeting.]

Date: 2009-10-15.00:00:00

Proposed resolution (October, 2009):

Add the following as a new paragraph at the end of 6.7.3 [basic.life]:

In this section, “before” and “after” refer to the “happens before” relation (6.9.2 [intro.multithread]). [Note: Therefore, undefined behavior results if an object that is being constructed in one thread is referenced from a different thread without adequate synchronization. —end note]
Date: 2008-05-03.00:00:00

Consider the following example:

    struct A {
      A() {
        std::thread(&A::Func, this).detach();
      }
      virtual void Func() {
        printf("In A");
      }
    };

    struct B : public A {
      virtual void Func() {
        printf("In B");
      }
    };

    struct C : public B {
      virtual void Func() {
        printf("In C");
      }
    };

    C c;

What is the program allowed to print? Should it be undefined behavior or merely unspecified which of the Func()s is called?

There is a related question about which variables C::Func() can depend on having been constructed. Unless we want to require the equivalent of at least memory_order_consume on the presumed virtual function table pointer, I think the answer is just the members of A.

If I instead just have

    A a;

I think the only reasonable behavior is to print In A.

Finally, given

    struct F {
      F() {
        std::thread(&F::Func, this).detach();
      }
      virtual void Func() {
        print("In F");
      }
    };

    struct G : public F {
    };

    G g;

I can see the behavior being undefined, but I think a lot of people would be confused if it did anything other than print In F.

Suggested resolution:

I think the intent here is that an object should not be used in another thread until any non-trivial constructor has been called. One possible way of saying that would be to add a new paragraph at the end of 11.9.5 [class.cdtor]:

A constructor for a class with virtual functions or virtual base classes modifies a memory location in the object that is accessed by any access to a virtual function or virtual base class or by a dynamic_cast. [Note: This implies that access to an object by another thread while it is being constructed often introduces a data race (see 6.9.2 [intro.multithread]). —end note]
History
Date User Action Args
2010-03-29 00:00:00adminsetmessages: + msg2719
2010-03-29 00:00:00adminsetstatus: ready -> cd2
2009-11-08 00:00:00adminsetmessages: + msg2366
2009-11-08 00:00:00adminsetstatus: drafting -> ready
2009-08-03 00:00:00adminsetstatus: open -> drafting
2008-05-03 00:00:00admincreate