Topic: volatile, was: memory visibility between threads


Author: Alexander Terekhov <terekhov@web.de>
Date: 9 Mar 2001 12:00:24 -0500
Raw View
James Kanze wrote:

> Alexander Terekhov wrote:
>
> > Do you see any problems if C++ would allow me to write:
>
> > struct A {
> >   Thread thread;
> >   A() : thread(this) { /*...*/ }
> >   ~A() { /*...*/ }
> >    virtual void run() = 0;
> > private:
> >   post A() { thread.start( /*...*/); /*thread_start_routine calls A::run*/}
> >   pre ~A() { thread.join(); /*stop*/ }
> > };
>
> > class T {
> > public:
> >    T() { /*...*/ }
> >   ~T() { /*...*/ }
> >    virtual void method() = 0;
> > private:
> >   post T() { xyz.register( this ); }
> >   pre ~T() { xyz.deregister( this ); }
> > };
>
> > ??
>
> I don't particularly see any problems that this would introduce into
> the language, but I don't see that it would really solve any either.

I think that one "problem" it would solve is the "problem" (error prone feature)
of virtual functions/use of "this" in constructors and destructors (12.7/3) -
just
do it "as usual" (this->f() calls the final overrider) in post-c-/pre-d-tors.

> The post T() is already possible, if you really need it.

post T() should go after the whole object is constructed (after constructor of
most-derived class) and should continue to do so even with more derived classes
added later with no modifications in "old" base classes (constructors) needed.
I would greatly appreciate it if you could show me how this could be done
with current C++ (and w/o virtual public inits or final wrapper class/chain
of inits or factories.

> If you need controlled registration and deregistration, it is easily
> implemented by means of a manager class, which serves as a factory,
> and to which the object is passed for deletion.

yes, I can delegate almost everything to manager classes/factories.
But look, post-c/pre-d-tors is nothing else but a kind of a simple
(easy to maintain) and exception-safe (with respect to already
completed post-c-tors/all c-tors) implicit _factory_. I find it more
convenient (simple, more readable and less error prone) if I would
be allowed to do things (closely related to my classes
e.g. controlled registration/deregistration, threading/synchronization,
etc) by means of post-c/pre-d-tors, which would serve as an implicit
factory.

regards,
alexander.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: porton@psu.ru (Victor Porton)
Date: 05 Mar 01 18:49:03 GMT
Raw View
In article <3A9F9961.CAF99F90@web.de>,
 Alexander Terekhov <terekhov@web.de> writes:
> James Kanze wrote:
>
>> Victor Porton wrote:
>>
>> > In article <3A9A4B33.D1BE33E9@dresdner-bank.com>,
>> >         James Kanze <James.Kanze@dresdner-bank.com> writes:
>> > > Gerhard Menzl wrote:
>>
>> > >> Post-constructors and pre-destructors would certainly be of help
>> > >> when it comes to solving that particular problem, but it is
>> > >> merely one example for the difficulties arising from the
>> > >> ignorance of threads by the C++ standard.
>>
>> > > I don't think that post-constructor and pre-destructor hooks would
>> > > really help here, and I don't really see where knowledge of
>> > > threads in the C++ language would help either. My impression is
>> > > that this is somewhat like the problem of making the standard
>> > > library thread-safe. The fact that any one operation in the
>> > > library is thread safe really doesn't buy you anything. Threading,
>> > > and thread safety, need to be analysed at a higher level; just
>> > > taking a single-threaded idiom and throwing synchronization at it
>> > > will NOT work.
>>
>> > Recall our problem:
>>
>> > struct A {
>> >   Thread thread;
>> >   A() : thread(this) { thread.start(); /*...*/ }
>> >     // oops, tread may use the object before it is fully constructed
>> >     // at point of /*...*/
>> >   ~A() { /*...*/ thread.stop(); }
>> >     // oops, tread may use the object during destruction
>> >     // at point of /*...*/
>> > };
>>
>> > So, we cannot start/stop thread during construction/destruction in
>> > this case. Too bad.
>>
>> I would say, that's life.  It's certainly not a C++ problem; the same
>> holds for Java, for example, and I would imagine, for every language
>> which supports both OO and threading.
>>
>> > Well, IMO, it is simpler. We do not need postconstructors. Simply
>> > standartizers should permit in the next C++ standard to use the
>> > object before it is fully constructed and after beginning of the
>> > destruction (and I think it is already so in most implementations).
>> > In such the case it would be of no problem.
>>
>> What can it possibly mean, to use the object before it is fully
>> constructed?  Java may not have the exact wording of the C++ standard
>> (in which anything but a very restricted use of the object is
>> undefined behavior), but the effect is the same -- an object which is
>> not fully constructed cannot be expected to work correctly.  It would
>> be trivial, for example, for the standard to require zero
>> initialization of all of the object before calling the base class
>> constructor (this is basically what Java does), but what would that
>> bring you?  The class invariants still haven't been estabilished, and
>> calling any member function will likely fail because of this.
>>
>> The problem has nothing to do with threading, really.  Until the class
>> is fully constructed, its invariants haven't been established, and any
>> attempt to use the class will result in undefined behavior.
>> Regardless of what the standard says.

If we start thread near of end of the body of the constructor, (part
of) class inveriants are already established. No problems with this.

But C++ standard does not allow using objects before ending of
construction, even if class inveriants are already established. It is
simply deficiency of the standard, but not a fundamental limitation.

Note that I am not subscribed to comp.std.c++, but only to
comp.lang.c++.moderated.

--
Don't write to the "From:" address!
Victor Porton (porton/&/narod.ru [/&/->@]; http://porton.narod.ru)

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: James Kanze <James.Kanze@dresdner-bank.com>
Date: 05 Mar 01 18:51:58 GMT
Raw View
Alexander Terekhov wrote:

> Do you see any problems if C++ would allow me to write:

> struct A {
>   Thread thread;
>   A() : thread(this) { /*...*/ }
>   ~A() { /*...*/ }
>    virtual void run() = 0;
> private:
>   post A() { thread.start( /*...*/); /*thread_start_routine calls A::run*/}
>   pre ~A() { thread.join(); /*stop*/ }
> };

> class T {
> public:
>    T() { /*...*/ }
>   ~T() { /*...*/ }
>    virtual void method() = 0;
> private:
>   post T() { xyz.register( this ); }
>   pre ~T() { xyz.deregister( this ); }
> };

> ??

I don't particularly see any problems that this would introduce into
the language, but I don't see that it would really solve any either.
The post T() is already possible, if you really need it.

If you need controlled registration and deregistration, it is easily
implemented by means of a manager class, which serves as a factory,
and to which the object is passed for deletion.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: Dima Volodin <dvv@dvv.org>
Date: 6 Mar 2001 08:00:27 -0500
Raw View
Victor Porton wrote:

> If we start thread near of end of the body of the constructor, (part
> of) class inveriants are already established. No problems with this.

> But C++ standard does not allow using objects before ending of
> construction, even if class inveriants are already established. It is
> simply deficiency of the standard, but not a fundamental limitation.

C++ standard does allow you to call member functions directly or indirectly
during construction or destruction, see 12.7/3. Note the rules for virtual
functions.

> Victor Porton (porton/&/narod.ru [/&/->@]; http://porton.narod.ru)

Dima
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: James Kanze <James.Kanze@dresdner-bank.com>
Date: 13 Mar 01 05:07:27 GMT
Raw View
Alexander Terekhov wrote:

> James Kanze wrote:

> > Alexander Terekhov wrote:

> > > Do you see any problems if C++ would allow me to write:

> > > struct A {
> > >   Thread thread;
> > >   A() : thread(this) { /*...*/ }
> > >   ~A() { /*...*/ }
> > >    virtual void run() = 0;
> > > private:
> > >   post A() { thread.start( /*...*/); /*thread_start_routine calls A::run*/}
> > >   pre ~A() { thread.join(); /*stop*/ }
> > > };

> > > class T {
> > > public:
> > >    T() { /*...*/ }
> > >   ~T() { /*...*/ }
> > >    virtual void method() = 0;
> > > private:
> > >   post T() { xyz.register( this ); }
> > >   pre ~T() { xyz.deregister( this ); }
> > > };

> > > ??

> > I don't particularly see any problems that this would introduce
> > into the language, but I don't see that it would really solve any
> > either.

> I think that one "problem" it would solve is the "problem" (error
> prone feature) of virtual functions/use of "this" in constructors
> and destructors (12.7/3) - just do it "as usual" (this->f() calls
> the final overrider) in post-c-/pre-d-tors.

I don't see where there is a problem here.  I find that C++ works
correctly the way it does; I use Java extensively, where the virtual
functions resolves to the future most derived type in constructors,
and I find that very error prone.

When you ask for a means of automatically calling a function (post)
after the complete construction, it sounds like you are proposing a
solution.  I want to know what problem it solves.  (I have only needed
to do this once, at that was because of a less than optimal design on
my part.)

For things like registering, you don't need the post function in a
single threaded environment, and it isn't sufficient in a
multithreaded.

> > The post T() is already possible, if you really need it.

> post T() should go after the whole object is constructed (after
> constructor of most-derived class) and should continue to do so even
> with more derived classes added later with no modifications in "old"
> base classes (constructors) needed. I would greatly appreciate it if
> you could show me how this could be done with current C++ (and w/o
> virtual public inits or final wrapper class/chain of inits or
> factories.

It's sufficient to make your constructor parameters a special type;
the constructor passes the address of the object to the argument
object, and the destructor of the argument object calls your function.
If the constructor would not otherwise take a parameter, make it take
one of this type, and default it to a temporary instance.  If it takes
a parameter, use an implicite convertion to the initializer type.

> > If you need controlled registration and deregistration, it is
> > easily implemented by means of a manager class, which serves as a
> > factory, and to which the object is passed for deletion.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: porton@psu.ru (Victor Porton)
Date: 01 Mar 01 04:24:20 GMT
Raw View
In article <3A9A4B33.D1BE33E9@dresdner-bank.com>,
 James Kanze <James.Kanze@dresdner-bank.com> writes:
> Gerhard Menzl wrote:
>
>> Post-constructors and pre-destructors would certainly be of help
>> when it comes to solving that particular problem, but it is merely
>> one example for the difficulties arising from the ignorance of
>> threads by the C++ standard.
>
> I don't think that post-constructor and pre-destructor hooks would
> really help here, and I don't really see where knowledge of threads in
> the C++ language would help either.  My impression is that this is
> somewhat like the problem of making the standard library thread-safe.
> The fact that any one operation in the library is thread safe really
> doesn't buy you anything.  Threading, and thread safety, need to be
> analysed at a higher level; just taking a single-threaded idiom and
> throwing synchronization at it will NOT work.

Recall our problem:

struct A {
  Thread thread;
  A() : thread(this) { thread.start(); /*...*/ }
    // oops, tread may use the object before it is fully constructed
    // at point of /*...*/
  ~A() { /*...*/ thread.stop(); }
    // oops, tread may use the object during destruction
    // at point of /*...*/
};

So, we cannot start/stop thread during construction/destruction in
this case. Too bad.

Well, IMO, it is simpler. We do not need postconstructors. Simply
standartizers should permit in the next C++ standard to use the object
before it is fully constructed and after beginning of the destruction
(and I think it is already so in most implementations). In such the
case it would be of no problem.

Note that I am not subscribed to comp.std.c++

--
Don't write to the "From:" address!
Victor Porton (porton/&/narod.ru [/&/->@]; http://porton.narod.ru)

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: James Kanze <James.Kanze@dresdner-bank.com>
Date: 02 Mar 01 03:36:13 GMT
Raw View
Victor Porton wrote:

> In article <3A9A4B33.D1BE33E9@dresdner-bank.com>,
>         James Kanze <James.Kanze@dresdner-bank.com> writes:
> > Gerhard Menzl wrote:

> >> Post-constructors and pre-destructors would certainly be of help
> >> when it comes to solving that particular problem, but it is
> >> merely one example for the difficulties arising from the
> >> ignorance of threads by the C++ standard.

> > I don't think that post-constructor and pre-destructor hooks would
> > really help here, and I don't really see where knowledge of
> > threads in the C++ language would help either. My impression is
> > that this is somewhat like the problem of making the standard
> > library thread-safe. The fact that any one operation in the
> > library is thread safe really doesn't buy you anything. Threading,
> > and thread safety, need to be analysed at a higher level; just
> > taking a single-threaded idiom and throwing synchronization at it
> > will NOT work.

> Recall our problem:

> struct A {
>   Thread thread;
>   A() : thread(this) { thread.start(); /*...*/ }
>     // oops, tread may use the object before it is fully constructed
>     // at point of /*...*/
>   ~A() { /*...*/ thread.stop(); }
>     // oops, tread may use the object during destruction
>     // at point of /*...*/
> };

> So, we cannot start/stop thread during construction/destruction in
> this case. Too bad.

I would say, that's life.  It's certainly not a C++ problem; the same
holds for Java, for example, and I would imagine, for every language
which supports both OO and threading.

> Well, IMO, it is simpler. We do not need postconstructors. Simply
> standartizers should permit in the next C++ standard to use the
> object before it is fully constructed and after beginning of the
> destruction (and I think it is already so in most implementations).
> In such the case it would be of no problem.

What can it possibly mean, to use the object before it is fully
constructed?  Java may not have the exact wording of the C++ standard
(in which anything but a very restricted use of the object is
undefined behavior), but the effect is the same -- an object which is
not fully constructed cannot be expected to work correctly.  It would
be trivial, for example, for the standard to require zero
initialization of all of the object before calling the base class
constructor (this is basically what Java does), but what would that
bring you?  The class invariants still haven't been estabilished, and
calling any member function will likely fail because of this.

The problem has nothing to do with threading, really.  Until the class
is fully constructed, its invariants haven't been established, and any
attempt to use the class will result in undefined behavior.
Regardless of what the standard says.

--
James Kanze                               mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: Alexander Terekhov <terekhov@web.de>
Date: 4 Mar 2001 10:32:05 -0500
Raw View
James Kanze wrote:

> Victor Porton wrote:
>
> > In article <3A9A4B33.D1BE33E9@dresdner-bank.com>,
> >         James Kanze <James.Kanze@dresdner-bank.com> writes:
> > > Gerhard Menzl wrote:
>
> > >> Post-constructors and pre-destructors would certainly be of help
> > >> when it comes to solving that particular problem, but it is
> > >> merely one example for the difficulties arising from the
> > >> ignorance of threads by the C++ standard.
>
> > > I don't think that post-constructor and pre-destructor hooks would
> > > really help here, and I don't really see where knowledge of
> > > threads in the C++ language would help either. My impression is
> > > that this is somewhat like the problem of making the standard
> > > library thread-safe. The fact that any one operation in the
> > > library is thread safe really doesn't buy you anything. Threading,
> > > and thread safety, need to be analysed at a higher level; just
> > > taking a single-threaded idiom and throwing synchronization at it
> > > will NOT work.
>
> > Recall our problem:
>
> > struct A {
> >   Thread thread;
> >   A() : thread(this) { thread.start(); /*...*/ }
> >     // oops, tread may use the object before it is fully constructed
> >     // at point of /*...*/
> >   ~A() { /*...*/ thread.stop(); }
> >     // oops, tread may use the object during destruction
> >     // at point of /*...*/
> > };
>
> > So, we cannot start/stop thread during construction/destruction in
> > this case. Too bad.
>
> I would say, that's life.  It's certainly not a C++ problem; the same
> holds for Java, for example, and I would imagine, for every language
> which supports both OO and threading.
>
> > Well, IMO, it is simpler. We do not need postconstructors. Simply
> > standartizers should permit in the next C++ standard to use the
> > object before it is fully constructed and after beginning of the
> > destruction (and I think it is already so in most implementations).
> > In such the case it would be of no problem.
>
> What can it possibly mean, to use the object before it is fully
> constructed?  Java may not have the exact wording of the C++ standard
> (in which anything but a very restricted use of the object is
> undefined behavior), but the effect is the same -- an object which is
> not fully constructed cannot be expected to work correctly.  It would
> be trivial, for example, for the standard to require zero
> initialization of all of the object before calling the base class
> constructor (this is basically what Java does), but what would that
> bring you?  The class invariants still haven't been estabilished, and
> calling any member function will likely fail because of this.
>
> The problem has nothing to do with threading, really.  Until the class
> is fully constructed, its invariants haven't been established, and any
> attempt to use the class will result in undefined behavior.
> Regardless of what the standard says.
>

Do you see any problems if C++ would allow me to write:

struct A {
  Thread thread;
  A() : thread(this) { /*...*/ }
  ~A() { /*...*/ }
   virtual void run() = 0;
private:
  post A() { thread.start( /*...*/); /*thread_start_routine calls A::run*/}
  pre ~A() { thread.join(); /*stop*/ }
};

class T {
public:
   T() { /*...*/ }
  ~T() { /*...*/ }
   virtual void method() = 0;
private:
  post T() { xyz.register( this ); }
  pre ~T() { xyz.deregister( this ); }
};

??

regards,
alexander.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]