Blog Archive for / cplusplus /
Reference Wrappers Explained
Wednesday, 14 July 2010
The
upcoming C++0x
standard includes reference wrappers in the form of
the std::reference_wrapper<T> class template, and
the helper function templates std::ref()
and std::cref(). As I mentioned in my blog post
on Starting
Threads with Member Functions and Reference Arguments, these
wrappers can be used to pass references to objects across interfaces
that normally require copyable (or at least movable) objects
— in that blog post, std::ref was used for passing
references to objects over to the new thread, rather than copying the
objects. I was recently asked what the difference was
between std::ref and std::cref, and how they
worked, so I thought I'd elaborate.
Deducing the Referenced Type
std::ref is a function template, so automatically
deduces the type of the wrapped reference from the type of the
supplied argument. This type deduction includes
the const-ness of the supplied object:
int x=3; const int y=4; std::reference_wrapper<int> rx=std::ref(x); // std::reference_wrapper<int> ry=std::ref(y); // error std::reference_wrapper<const int> rcy=std::ref(y);
On the other hand, though std::cref also deduces the
type of the wrapped reference from the supplied argument,
it always wraps a const reference:
int x=3; const int y=4; // std::reference_wrapper<int> rx=std::cref(x); // error std::reference_wrapper<const int> rcx=std::cref(x); // std::reference_wrapper<int> ry=std::cref(y); // error std::reference_wrapper<const int> rcy=std::cref(y);
Since a no-const-reference can always be bound to
a const reference, you can thus
use std::ref in pretty much every case where you would
use std::cref, and your code would work the same. Which
begs the question: why would you ever choose to
use std::cref?
Using std::cref to prevent modification
The primary reason for choosing std::cref is because
you want to guarantee that the source object is not modified through
that reference. This can be important when writing multithreaded
code — if a thread should not be modifying some data then it
can be worth enforcing this by passing a const
reference rather than a mutable reference.
void foo(int&); // mutable reference int x=42; // Should not be modified by thread std::thread t(foo,std::cref(x)); // will fail to compile
This can be important where there are overloads of a function such
that one takes a const reference, and the other a
non-const reference: if we don't want the object
modified then it is important that the overload taking
a const reference is chosen.
struct Foo
{
void operator()(int&) const;
void operator()(int const&) const;
};
int x=42;
std::thread(Foo(),std::cref(x)); // force const int& overload
References to temporaries
std::cref has another property missing
from std::ref — it can bind to temporaries, since
temporary objects can bind to const references. I'm
not sure this is a good thing, especially when dealing with multiple
threads, as the referenced temporary is likely to have been
destroyed before the thread has even started. This is therefore
something to watch out for:
void bar(int const&); std::thread t(bar,std::cref(42)); // oops, ref to temporary
Documentation
Finally, std::cref serves a documentation purpose,
even where std::ref would suffice — it declares
in big bold letters that this reference cannot be used to modify the
referenced object, which thus makes it easier to reason about the
code.
Recommendation
I would recommend that you use std::cref in preference
to std::ref whenever you can — the benefits as
documentation of intent, and avoiding accidental modification
through the reference make it a clear winner in my opinion. Of
course, if you do want to modify the referenced
object, then you need to use std::ref, but such usage
now stands out, and makes it clear that this is the intent.
You do still need to be careful to ensure that you don't try and
wrap references to temporaries, particularly when
applying std::cref to the result of a function call,
but such uses should stand out — I expect most uses to be
wrapping a reference to a named variable rather than wrapping a
function result.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: reference wrappers, ref, cref, cplusplus
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
Last day for comments on the C++0x FCD
Thursday, 17 June 2010
The BSI deadline for comments on the C++0x FCD is tomorrow, Friday 18th June 2010. The ISO deadline is 26th July 2010, but we have to write up comments for submission in the form required for ISO, which takes time.
If you have a comment on the FCD, please see my earlier blog post for how to submit it to BSI. Help us make the C++0x standard as good as it can be.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++, C++0x, WG21, FCD
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
March 2010 C++ Standards Committee Mailing
Thursday, 08 April 2010
The March 2010 mailing for the C++ Standards Committee was published last week. This is the post-meeting mailing for the March 2010 committee meeting, and contains the C++0x Final Committee Draft, which I blogged about last week.
There are 6 concurrency-related papers (of which my name is on two), which I summarize below:
Concurrency-related papers
- N3057: Explicit Initializers for Atomics
This paper proposes new initializers for atomic variables, providing a means of writing code which can be compiled as either C or C++. e.g.
void foo() { atomic_int a=ATOMIC_VAR_INIT(42); // initialize a with 42 atomic_uint b; // uninitialized atomic_init(&b,123); // b now initialized to 123 }- N3058: Futures and Async Cleanup (Rev.)
This is a revision of N3041 to resolve many of the outstanding issues with futures and async. Mostly it's just wordsmithing to tidy up the specification, but there's a few key changes:
- Defined behaviour for
the
wait_for()andwait_until()member functions ofstd::future,std::shared_futureandstd::atomic_futurewhen used withstd::asyncand a launch policy ofstd::launch::sync. The return value is now a value of the newstd::future_statusenumeration, and can bestd::future_status::readyif the future becomes ready before the timeout,std::future_status::timeoutif the wait times out, orstd::future_status::deferredif the future comes from a call tostd::asyncwith a launch policy ofstd::launch::syncand the function associated with the future hasn't yet started execution on any thread. - The wording
for
std::asyncadopts the same wording asstd::threadto clarify the copy/move and perfect forwarding semantics of the call.
- Defined behaviour for
the
- N3069: Various threads issues in the library (LWG 1151)
This is a revision of N3040, and highlights which operations through iterators constitute accesses and data races, and explicitly allows for synchronization by writing and reading to/from a stream.
- N3070:
Handling Detached Threads and
thread_localVariables This is a hugely simplified replacement for my previous paper N3038. Rather than creating contexts for
thread_localvariables, this paper proposes new member functions forstd::promiseandstd::packaged_taskto allow the value to be set at the point of call, but threads waiting on associated futures to be woken only afterthread_localvariables have been destroyed at thread exit. This means that you can now safely wait on a future which is set in such a fashion when waiting for a task running on a background thread to complete, without having to join with the thread or worry about races arising from the destructors ofthread_localvariables. The paper also adds a similar mechanism for condition variables as a non-member function.- N3071:
Renaming
launch::anyand what asyncs really might be (Rev.) This is a revision of N3042 proposing renaming
std::launch::anytostd::launch::sync_or_async. This paper was not approved.- N3074: Updates to C++ Memory Model Based on Formalization
This is a revision of N3045. This paper proposes some changes to the wording of the memory model in order to ensure that it means what we intended it to mean.
Other Papers
There's several non-concurrency papers in the mailing as well as the standard set (working draft, agenda, issues lists, etc.). The most significant of these in my view are the following 3 papers. Check the mailing for the full set.
- N3050: Allowing Move Constructors to Throw (Rev. 1)
This paper adds the new
noexceptkeyword to C++. This is used in place of an exception specification. On its own it means that the function does not throw any exceptions, but it can also be used with a boolean constant expression wheretruemeans that the function doesn't throw, andfalsemeans that it might. e.g.void foo() noexcept; // will not throw void bar() noexcept(true); // will not throw void baz() noexcept(false); // may throw
If a
noexceptexception specification is violated thenstd::terminate()is called.The primary benefit from the boolean-constant-expression version is in templates, where the boolean expression can check various properties of the template parameter types. One of the things you can check is whether or not particular operations throw, e.g. by using the new
has_nothrow_move_constructortype trait to declare the move constructor for a class to benoexceptif its class members have non-throwing move constructors:template<typename T> class X { T data; public: X(X&& other) noexcept(std::has_nothrow_move_constructor<T>::value): data(std::move(other.data)) {} };- N3053: Defining Move Special Member Functions
This proposal ensures that user-defined classes have move constructors and move assignment operators generated for them by the compiler if that is safe. Explicitly declaring a copy or move constructor will prevent the implicit declaration of the other, and likewise for copy and move assignment. You can always request the default definition using the
= defaultsyntax.This means that lots of user code will now be able to readily take advantage of move semantics with a simple code change or even just a recompile. This can potentially be of major performance benefit.
- N3055: A Taxonomy of Expression Value Categories
This paper nails down the true distinctions between lvalues, rvalues and rvalue references. It provides a new set of names to identify the distinct categories of values in C++ — lvalues and rvalues we already have, but now there's xvalues, prvalues and glvalues too. This categorization allows for better specification of when things can bind to lvalue references or rvalue references, when the compiler can eliminate copies or moves.
Please comment on the FCD
The purpose of the C++0x Final Committee Draft is to get comments prior to publication to ensure the final C++0x standard is as defect free as possible. This opportunity is only available for a limited time, so please comment on the FCD.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
C++0x Final Committee Draft Published - Please Comment
Friday, 02 April 2010
Earlier this week, the Final Committee Draft (FCD) of the C++0x standard was published. This means that C++0x is now in the final stages of bug fixing and wordsmithing before publication. If all goes to plan, the draft will move to Final Draft International Standard (FDIS) early in 2011, and will be a new standard by the end of 2011.
The publication of the FCD means that the draft standard has now been officially put up for review by the national standards bodies of ISO's member countries. The British Standards Institution is one of several national bodies that is actively involved in the standardisation of the C++ language. The panel members of the C++ Committee of the BSI, IST 5/-/21, are currently compiling a list of comments on the FCD. We intend to submit these as the BSI's National Body comments, aimed at getting issues with the FCD addressed before it becomes the new international standard for C++.
We're welcoming additional comments, and would like to provide a channel for anyone who may be interested in the C++0x Standard, but not able to be fully involved in the standards process, to submit comments. Note that not all comments — regardless of whether they are submitted by panel members or non-members — will go forward.
Here is some guidance on what we are looking for:
- Suggestions for how to improve the clarity of the wording, even if that's just by adding a cross-reference to a relevant paragraph elsewhere;
- Comments that identify any under/over specification; and
- Comments highlighting inconsistencies or contradictions in the draft text.
Comments should be specific and preferably should include suggested updated wording (and if you need help formulating updated wording we can provide it, within reason) — the C++ standards committee is working to a very tight schedule in order to get C++0x out as soon as possible, and comments without wording (which therefore require more work from the committee) are more likely to be rejected.
The time for adding/removing features has now passed, so comments should focus on improving the draft as it stands rather than suggesting new features.
Owing to the time scale for submission to BSI and ISO, comments need to be submitted by Friday 18th June 2010.
If you have any comments, feel free to post them in the comment section of this blog entry, or email them to me. I will forward all appropriate suggestions to the rest of the BSI panel (whether or not I agree with them).
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++, C++0x, WG21, FCD
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
February 2010 C++ Standards Committee Mailing
Tuesday, 23 February 2010
The February 2010 mailing for the C++ Standards Committee was published last week. This is the pre-meeting mailing for the March 2010 committee meeting and contains a new working draft.
There are 5 concurrency-related papers (of which my name is on one), which I summarize below:
Concurrency-related papers
- N3038:
Managing the lifetime of
thread_localvariables with contexts (Revision 2) This is my paper on creating contexts for
thread_localvariables. The use of such contexts allows you to control when variables that are declared asthread_localare destroyed. It is a revision of my previous paper N2959; the primary change is that contexts can now be nested, which allows library code to use them without having to know whether or not a context is currently active.- N3040: Various threads issues in the library (LWG 1151)
This paper by Hans Boehm seeks to address LWG issue 1151. The key issue is to ensure that it is clear which operations may constitute a data race if they run concurrently without synchronization.
- N3041: Futures and Async Cleanup
The adoption of multiple papers affecting futures and
std::asyncat the same C++ committee meeting meant that the wording ended up being unclear. Detlef Vollmann kindly volunteered to write a paper to resolve these issues, and this is it.Unfortunately, I think that some of the wording is still unclear. I also dislike Detlef's proposal to force the
wait_forandwait_untilmember functions of the future types to throw exceptions if the future was created from a call tostd::asyncwith a launch policy ofstd::launch::sync. My preferred alternative is to change the return type fromboolto an enumeration with distinct values for if the future is ready, if the wait timed out, or if the future holds a deferred function fromstd::launch::syncthat has not yet started. This would be similar to the current behaviour ofstd::condition_variable::wait_forandstd::condition_variable::wait_until, which return astd::cv_statusenumeration value.- N3042:
Renaming
launch::anyand what asyncs really might be This is another paper from Detlef Vollmann proposing renaming
std::launch::anytostd::launch::any_sync. His rationale is that future revisions of the C++ standard may wish to add values to thestd::launchenumeration for additional types of async calls that should not be covered bystd::launch::any. Personally, I think this is a non-issue, and should be covered as and when such values are added.- N3045: Updates to C++ Memory Model Based on Formalization
Following attempts to create a mathematical formalization of the memory model it became clear that some cases were unclear or ambiguous or did not guarantee the desired semantics. This paper proposes some changes to the wording of the memory model in order to ensure that it means what we intended it to mean.
Other Papers
There's several non-concurrency papers in the mailing as well as the standard set (working draft, agenda, issues lists, etc.). The most significant of these in my view is N3044 which proposes compiler-defined move constructors and assignment operators. Check the mailing for the full set.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
The difference between struct and class in C++
Sunday, 21 February 2010
I've seen a lot of people asking about the differences
between the use of the struct and class
keywords in C++ lately. I don't know whether there's an influx of
C++ programmers due to the upcoming C++0x standard, or whether I've
just noticed people asking questions that haven't caught my eye
before. Whatever the reason, I'm writing this blog entry as
something I can point to the next time someone asks the
question.
Declaring and defining user-defined types
The primary use of both the struct
and class keywords is to define a user-defined type. In
C++, such a user-defined type is termed a "class" regardless of
which keyword is used in the definition. The choice of keyword is in
one sense arbitrary, since the same features and facilities are
available whichever keyword is used — there is only one
semantic difference which we shall look at shortly. The following
two class definitions are thus equivalent in all respects apart from
the names of the classes:
struct type_a
{
private:
int data;
public:
type_a(int data_):
data(data_)
{}
virtual void foo()=0;
virtual ~type_a()
{}
};
class type_b
{
private:
int data;
public:
type_b(int data_):
data(data_)
{}
virtual void foo()=0;
virtual ~type_b()
{}
};
As this little example shows, you can have constructors,
destructors, member functions, private members and even virtual
member functions in a class declared with the struct
keyword, just as you can with a class declared using
the class keyword. Though this example doesn't show it,
you can also use the struct keyword to declare classes
with base classes.
You can even forward-declare your class using one keyword and then define it with the other, though compilers have been known to complain about this usage:
struct foo;
class foo {};
class bar;
struct bar {};
So, what of the minor semantic difference then? The change is in
the default access specifier for members and base
classes. Though classes defined using either keyword can
have public, private
and protected base classes and members, the default
choice for classes defined using class
is private, whilst for those defined
using struct the default is public. This
is primarily for backwards compatibility with C: the members of a C
structure can be freely accessed by all code so in order to allow
existing C code to compile unchanged as C++ the default access
specifier for members of a class declared with struct
must be public. On the other hand, private data is a
key aspect of the encapsulation aspect of object-oriented design, so
this is the default for those classes declare
with class.
C doesn't have inheritance, but the default access specifier for
base classes varies with the keyword used to declare the derived
class too. It is public for classes declared
with struct and private for those declared
with class just the same as for data members. You can
still override it with an explicit specifier in both cases.
Let's take a quick look at some examples to see how that works:
struct s1
{
int a; // public
private:
int b; // private
protected:
int c; // protected
public:
int d; // public again
};
class c1
{
int a; // private
private:
int b; // still private
protected:
int c; // protected
public:
int d; // public
};
struct s2:
s1, // public
private c1, // private
type_b, // public again
protected foo, // protected
public bar // public again
{};
class c2:
s1, // private
private c1, // still private
type_b, // private again
protected foo, // protected
public bar // public
{};
As far as declaring and defining user-defined types in C++, that is
the only difference; in all other respects, classes declared
with struct are identical to those declared
with class.
C Compatibility
We touched on this a bit earlier: classes declared with
the struct keyword can be compiled as C if they don't
use any features that are C++ specific. Thus the following is both a
valid C++ class and a valid C structure:
struct c_compatible
{
int i;
char c;
double d;
};
It is therefore common to see struct used in header
files that are shared between C and C++. Since non-virtual member
functions don't affect the class layout you can even have member
functions in such a type, provided they are hidden from the C
compiler with a suitable #ifdef:
struct baz
{
int i;
#ifdef __cplusplus
void foo();
#endif;
};
Templates
There is one place where you can use the class keyword
but not the struct one, and that is in the declaration
of a template. Template type parameters must be declared using
either the class or typename
keyword; struct is not allowed. The choice
of class or typename in this case is again
arbitrary — the semantics are identical. The choice of keyword
does not impose any semantic meaning, any type (whether a built in
type like int or a user-defined type like a class or
enumeration) can be used when instantiating the template in either
case.You can of course declare a class template with
the struct keyword, in which case the default access
for the members of the template is public.
template<class T> // OK
void f1(T t);
template<typename T> // OK
void f2(T t);
template<struct T> // ERROR, struct not allowed here
void f3(T t);
template<class T>
struct S
{
T x; // public member
};
That's all folks!
These are the only concrete distinctions between the uses of
the struct keyword and the class keyword
in C++. People also use them for documentation purposes,
reserving struct for C-compatible classes, or classes
with no member functions, or classes with no private data, or
whatever their coding standard says. However, this is just
documentation and convention rather than an inherent difference: you
could use struct for all your classes,
or class for all your classes except those that are
shared with C.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
November 2009 C++ Standards Committee Mailing
Tuesday, 17 November 2009
The November 2009 mailing for the C++ Standards Committee was published last week. This is the post-meeting mailing for the October committee meeting and contains a new working draft incorporating all the proposals accepted at the October meeting.
As those of you who
read Herb
Sutter's blog
or Michael
Wong's blog will already know, the big news for concurrency is
that a proposal for std::async has been
accepted, and this is reflected in the latest working
draft.
There are 5 concurrency-related papers (of which my name is on one), which I summarize below:
Concurrency-related papers
- N2985: C and C++ Thread Compatibility
Lawrence Crowl has been through the concurrency and multithreading support from the C++ working draft, and compared this to that now being added to the C working draft for the next C standard. This paper contains his observations and recommendations about the potential for compatibility between the types and functions provided by the two draft standards. I agree with some of his recommendations, and disagree with others. No action will be taken by the C++ committee unless his recommendations become full proposals.
- N2992: More Collected Issues with Atomics
This is Lawrence Crowl's paper which rounds up various issues with the C++ atomics. It was accepted by the committee, and has been incorporated into the working draft. The most noticeable change is that the atomic types and functions now live in the
<atomic>header. The macro for identifying lock-free atomics has been expanded into a set of macros, one per type, and a guarantee has been added that all instances of a type are lock-free, or all are not lock-free (rather than it being allowed to vary between objects). There is also a clarification that if you use compare-exchange operations on a type with padding bits then the padding bits will be part of the comparison (which will therefore affectatomic<float>or similar), plus a few other clarifications.- N2996: A Simple Asynchronous Call
This paper is by Herb Sutter and Lawrence Crowl, and brings together their papers from the pre-meeting mailing (N2970 and N2973) based on feedback from the committee. This is the
std::asyncproposal that got accepted, and which has been incorporated into the working draft.The result is that we have a variadic
asyncfunction with an optional launch policy as the first argument, which specifies whether the function is to be spawned on a separate thread, deferred untilget()orwait()is called on the returnedfuture, or either, at the choice of the implementation.- N2997: Issues on Futures (Rev. 1)
This is a revision of N2967 from the pre-meeting mailing, which incorporates feedback from the committee. This is the version that was accepted, and which has been incorporated into the working draft. The key change is that
unique_futurehas been renamed to justfuturein order to make things easier to read in what is anticipated to be the common case.- N2999: Background for issue 887: Clocks and Condition Variables (Rev. 1)
This is a minor revision of Detlef's paper from the pre-meeting mailing (N2969). The changes it proposes have not yet been accepted into the working paper, and will make it implementation-dependent which clocks can be used for condition variable waits.
Other concurrency changes in the working draft
std::mutexnow has aconstexprconstructor, so namespace-scope objects are guaranteed to be safe from initialization order issues.- The return type of the
wait_forandwait_untilmember functions ofstd::condition_variableandstd::condition_variable_anyhas been changed from aboolto acv_statusenum. This makes it clear whether the return is due to a signal (or spurious wake) or because the operation timed out.
Updated implementation
Our just::thread
implementation of the C++0x thread library will shortly be updated
to incorporate all these changes (including an implementation
of std::async). Existing customers will get a free
upgrade as usual.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
September 2009 C++ Standards Committee Mailing
Wednesday, 30 September 2009
The September 2009 mailing for the C++ Standards Committee was published today. This is the pre-meeting mailing for the October committee meeting and contains the first new working draft since the "Concepts" feature was voted out of C++0x in July.
There is also quite a large number of papers in this mailing, including 7 concurrency-related papers (of which my name is on 2), which I summarize below:
Concurrency-related papers
- N2955: Comments on the C++ Memory Model Following a Partial Formalization Attempt
Mark has been working on a formal model for parts of the C++ memory model, and has identified a few cases where the wording could be improved to clarify things.
- N2959: Managing the lifetime of thread_local variables with contexts (Revision 1)
This is a revision of my earlier paper, N2907 which expands my proposal for a
thread_local_contextclass, along with full proposed wording. I think this provides a workable solution to the general problem of ensuring that destructors forthread_localvariables are run at particular points in the execution of a program as discussed in N2880.- N2967: Issues on Futures
This paper that I co-authored with Detlef Vollmann provides a complete rewording for the "Futures" section of the standard (30.6). It folds the proposed changes from N2888 in with changes requested by the LWG at July's meeting (including the addition of a new future type —
atomic_futurewhich serializes all operations), and editorial comments on the earlier wording. It doesn't resolve everything — there is still some discussion over whetherunique_future::get()should return a value or a reference, for example — but it provides a sound basis for further discussion.- N2969: Background for issue 887: Clocks and Condition Variables
Detlef argues the case that
std::condition_variable::wait_forandstd::condition_variable::wait_untilmay wake "too late" if the user adjusts the system clock during a wait, and suggests simplifying the overload set to match the minimum requirements of POSIX. LWG has already decided that this is Not A Defect (NAD), and I agree — there are no guarantees about how soon after the specified timeout the wait will return, and this is thus entirely a quality of implementation issue.- N2970: A simple async() (revision 1)
This is a revision to Herb Sutter's take on a
std::asyncfunction. There is a lot of discussion around the various issues, but the proposed wording seems incomplete — for example, if theunique_futureassociated with asynchronousasynccall is moved into ashared_futurewhich is then copied, which call toget()runs the task?- N2973: An Asynchronous Call for C++
This is a revision to Lawrence Crowl's take on a
std::asyncfunction. Whilst better specified than N2970 (a "serial" task is invoked inunique_future::get()or when theunique_futureis moved into ashared_future), I'm not entirely happy with the result.- N2974: An Analysis of Async and Futures
To aid the committee with deciding on the semantics of
std::async, Lawrence has put together this paper which outlines various options for creating futures from anasyncfunction. He then goes on to outline the operations that we may wish to perform on those futures, and how they relate to the various options forasync.
As you can see by the 3 papers on the issue,
std::async is a hot topic. I hope that a single coherent
design can be agreed on at Santa Cruz, and incorporated into the
standard. Comment
on this blog post if you've got an opinion on the matter, and I'll
pass it on.
Other papers
As I said at the beginning of this post, there are quite a few papers in this mailing. Other than the new working draft, there were 3 papers that piqued my interest:
- N2954: Unified Function Syntax which proposes allowing lambda-style syntax for normal functions,
- N2953: Defining Move Special Member Functions which covers the implicit generation of move constructors and move assignment operators, and
- N2951:
forward which covers the usage and constraints on
std::forward
Other papers include changes to the allocator proposals, papers to cover specific core issues, a couple of papers on type traits and a couple on pairs and tuples. See the full paper list for further details.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
August 2009 C++ Standards Committee Mailing
Thursday, 06 August 2009
The August 2009 mailing for the C++ Standards Committee was published yestoday. This is the post-meeting mailing for the July committee meeting. There isn't a new working draft this time, for one very simple reason: the "Concepts" feature was voted out of C++0x, so huge sections of the draft will have to be changed. Thankfully, the concurrency-related parts had not yet had concepts applied, so will not be affected directly by this.
C++0x timetable
What does this mean for the timetable? Well, the committee currently intends to issue a new Committee Draft for voting and comments by National Bodies in March 2010. How long it takes to get from that draft to a new Standard will depend on the comments that come back, and the length of the committee's issue lists. This is not intended to be a Final Committee Draft, implying there would be at least one more round of voting and comments. As I understand it, the earliest we could get a new Standard is thus early 2011, though if that were to be the case then the details would be finalised late 2010.
Concurrency-related papers
This time, there's only one concurrency-related paper in the mailing:
- N2925: More Collected Issues with Atomics
This paper gathers together the proposed wording for a number of outstanding issues with respect to the atomic data types. This tightens up the wording regards the memory ordering guarantees of fences, and adjusts the overload set for both free functions and member functions to ensure atomics behave sensibly in more circumstances. Crucially, the header for atomic operations is also changed — rather than the <cstdatomic> / <stdatomic.h> pairing from the previous draft there is a single header: <atomic>.
Future developments
Though futures were discussed, no change was made to the working paper in this regard. Detlef and I have been asked to write a further paper on the topic to incorporate the issues raised at the meeting, which will therefore be in the next committee mailing.
Likewise, the proposals for dealing with the lifetime of
thread_local variables and for launching an asynchronous
task with a return value are still under discussion, and further
papers on those can be expected.
Your input
How do you feel about the removal of concepts? Do you think the slip in schedule will have an impact on you? Let me know in the comments.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.
June 2009 C++ Standards Committee Mailing - New Working Draft and Concurrency Papers
Wednesday, 24 June 2009
The June 2009 mailing for the C++ Standards Committee was published today. This is the pre-meeting mailing for the upcoming committee meeting. Not only does it include the current C++0x working draft, but there are 39 other papers, of which 6 are concurrency related.
Concurrency-related papers
- N2880: C++ object lifetime interactions with the threads API
This is a repeat of the same paper from the May 2009 mailing. It is referenced by several of the other concurrency papers.
- N2888: Moving Futures - Proposed Wording for UK comments 335, 336, 337 and 338
This is the first of my papers in this mailing. The current working draft restricts
std::unique_futureto beMoveConstructible, but notMoveAssignable. It also restrictsstd::shared_futurein a similar way, by making itCopyConstructible, but notCopyAssignable. This severely limits the potential use of such futures, so the UK panel filed comments on CD1 such as UK comment 335 which requested relaxation of these unnecessary restrictions. This paper to provide a detailed rationale for these changes, along with proposed wording.- N2889: An Asynchronous Call for C++
This is the first of two papers in the mailing that proposes a
std::async()function for starting a task possibly asynchronously and returning a future for the result from that task. This addresses a need identified by UK comment 329 on CD1 for a simple way of starting a task with a return value asynchronously.- N2901: A simple async()
This is the second of the papers in the mailing that proposes a
std::async()function for starting a task possibly asynchronously and returning a future for the result from that task.The primary difference between the papers is the type of the returned future. N2889 proposes a new type of future (
joining_future), whereas N2901 proposes usingstd::unique_future. There are also a few semantic differences surrounding whether tasks that run asynchronously aways do so on a new thread, or whether they may run on a thread that is reused for multiple tasks. Both papers provide a means for the caller to specify synchronous execution of tasks, or to allow the implementation to decide between synchronous execution and asynchronous execution on a case-by-case basis. N2901 also explicitly relies on the use of lambda functions orstd::bindto bind parameters to a call, whereas N2889 supports specifying function arguments as additional parameters, as per thestd::threadconstructor (see my introduction to starting threads with arguments in C++0x).Personally, I prefer the use of
std::unique_futureproposed in N2901, but I rather like the argument-passing semantics of N2889. I also think that thethread_localissues can be addressed by my proposal for that (N2907, see below). A final concern that I have is that calling the task insidefuture::get()can yield surprising behaviour, as futures can be passed across threads, so this may end up being called on another thread altogether. For synchronous execution, I would prefer invoking the task inside thestd::asynccall itself, but delaying it to theget()does allow for work-stealing thread pools.- N2907: Managing the lifetime of thread_local variables with contexts
This is the second of my papers in this mailing. It proposes a potential solution to the lifetime-of-
thread_local-variables issues from N2880 discussed in last month's blog post.The idea is that you manage the lifetime of
thread_localvariables by constructing an instance of a new classstd::thread_local_context. When thestd::thread_local_contextinstance is destroyed, allthread_localvariables created in that context are also destroyed. You can then construct a subsequent instance ofstd::thread_local_context, and create newthread_localinstances in that new context. This means that you can reuse a thread for multiple unrelated tasks, without "spilling"thread_localvariables from an earlier task into later tasks. It can also be used with astd::async()function to ensure that thethread_localvariables are destroyed before the associated future is made ready.- N2917: N2880 Distilled, and a New Issue With Function Statics
This is Herb Sutter's take on the issues from N2880. He starts with a general discussion of the issue with detached threads and static destruction of globals, and then continues with a discussion of the issues surrounding the destruction of function-scoped
thread_localvariables. In particular, Herb focuses on something he calls Functionthread_localstatics poisoningthread_localdestructors — if the destructor of athread_localobjectxcalls a function that itself uses a function-scopethread_localy, then the destructor ofymight already have been called, resulting in undefined behaviour.I found Herb's coverage of the issues surrounding detached threads dismissive of the idea that people could correctly write manual synchronization (e.g. using a
std::condition_variableor astd::unique_future), even though this is common practice amongst those using POSIX threads (for example, in David Butenhof's Programming with POSIX Threads, he says "pthread_join is a convenience, not a rule", and describes examples using detached threads and condition variables to signal when the thread is done). I can see many possibilities for such usage, so as a consequence, I am personally in favour of his "solution" 1D: leave things as they are with regard to detached threads — it is already undefined behaviour to access something after its destruction.However, the issue Herb raises with regard to order of destruction for
thread_localvariables is important, and not something that mystd::thread_local_contextproposal addresses. As Herb points out, the problem does exist with regard to function-localstaticvariables already —thread_localjust amplifies the problem. I am inclined to go with what POSIX threads does, and whatboost::thread_specific_ptrdoes: make them "phoenix" variables that are re-initialized when accessed after destruction, and are thus added back onto the destructor list. This is Herb's solution 2B.
Other papers
Now that CD1 is out, and the committee is trying to get things pinned down for CD2, Concepts are getting a lot of discussion. There are therefore several papers on Concepts in the mailing. There are also papers on automatically defining move constructors, revised wording for lambdas, a proposal for unifying the function syntax, and several others. Check out the full list of papers for details.
Your comments
Do you have any comments on the papers (especially the concurrency
ones, but if you have any comments on the others I'd like to know
too)? Which std::async proposal do you prefer, or do you
like aspects of both or neither? Do you think that
thread_local_context objects combined with resurrecting
thread_local objects on post-destruction access solves
the thread_local issues?
Let me know by posting a comment.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards, concurrency
Stumble It!
| Submit to Reddit
| Submit to DZone ![]()
If you liked this post, why not subscribe to the RSS feed
or Follow me on Twitter? You can also subscribe to this blog by email using the form on the right.