Topic: c++0x: Resetting once_flag


Author: Joe Gottman <jgottman@carolina.rr.com>
Date: Wed, 12 Aug 2009 01:55:21 CST
Raw View
  As I understand it, the only things that can be done with
std::once_flag are to default-construct it and to pass it to the first
parameter of std::call_once. So, in the following code the function f
will only be called once.

void f();

int main()
{
  once_flag flag;
  call_once(flag, f);
  call_once(flag, f);
}

After call_once has been called on a once_flag, is there any way of
resetting the once_flag so that it is again in its default-constructed
state?  The use-case I'm thinking of is a class with a mutable data
member that is lazily computed and whose value depends on the value of
some other data member.  If the other data member is changed, I would
want to recompute the mutable data member the next time a user
accesses it.

class Foo {
  private:
       string fileName_;
       mutable once_flag flag_;

       // A large, expensive-to-initialize object that isn't always needed.
       mutable LargeObject largeObject;

      // Initializes largeObject_ depending on value of fileName_
      void loadLargeObject() const;
  public:
     const LargeObject &getLargeObject()
     {
       call_once(&loadLargeObject, *this);
       return largeObject_;
     }

     const string &getFileName() const {return fileName_;}
     void setFileName(const string &filename)
     {
       flag_ = once_flag(); // Reset flag to initial state;
       largeObject_ = LargeObject();// Reset large Object to default state
     }
};


Joe Gottman


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Anthony Williams <anthony.ajw@gmail.com>
Date: Wed, 12 Aug 2009 11:55:52 CST
Raw View
Joe Gottman <jgottman@carolina.rr.com> writes:

>  As I understand it, the only things that can be done with
> std::once_flag are to default-construct it and to pass it to the first
> parameter of std::call_once.

> After call_once has been called on a once_flag, is there any way of
> resetting the once_flag so that it is again in its default-constructed
> state?

No.

> The use-case I'm thinking of is a class with a mutable data
> member that is lazily computed and whose value depends on the value of
> some other data member.  If the other data member is changed, I would
> want to recompute the mutable data member the next time a user
> accesses it.

Then once_flag/call_once isn't what you need. In single-threaded code
you could just use a simple boolean flag.

In multi-threaded code you need to be more careful. Even if once_flag
did allow being reset, there'd be a race between code that called the
function using call_once and the reset code, since the reset code would
not be able to reset the once_flag AND reset the associated data as a
single atomic action. If you know there's no race here due to the
structure of the code (the get and reset functions will never be called
concurrently), then you could just use an atomic_bool flag.

If the get and reset functions CAN be called concurrently then you will
need to protect the cached LargeObject with a mutex.

Your question inspired me to write a blog post about this:
http://www.justsoftwaresolutions.co.uk/threading/multithreading-in-c++0x-part-6-double-checked-locking.html

Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library   | http://www.stdthread.co.uk
Just Software Solutions Ltd         | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]