Blog Archive for / cplusplus /
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 left.
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_future
to beMoveConstructible
, but notMoveAssignable
. It also restrictsstd::shared_future
in 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::bind
to bind parameters to a call, whereas N2889 supports specifying function arguments as additional parameters, as per thestd::thread
constructor (see my introduction to starting threads with arguments in C++0x).Personally, I prefer the use of
std::unique_future
proposed in N2901, but I rather like the argument-passing semantics of N2889. I also think that thethread_local
issues 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::async
call 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_local
variables by constructing an instance of a new classstd::thread_local_context
. When thestd::thread_local_context
instance is destroyed, allthread_local
variables created in that context are also destroyed. You can then construct a subsequent instance ofstd::thread_local_context
, and create newthread_local
instances in that new context. This means that you can reuse a thread for multiple unrelated tasks, without "spilling"thread_local
variables from an earlier task into later tasks. It can also be used with astd::async()
function to ensure that thethread_local
variables 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_local
variables. In particular, Herb focuses on something he calls Functionthread_local
statics poisoningthread_local
destructors — if the destructor of athread_local
objectx
calls a function that itself uses a function-scopethread_local
y
, then the destructor ofy
might 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_variable
or 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_local
variables is important, and not something that mystd::thread_local_context
proposal addresses. As Herb points out, the problem does exist with regard to function-localstatic
variables already —thread_local
just amplifies the problem. I am inclined to go with what POSIX threads does, and whatboost::thread_specific_ptr
does: 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 left.
May 2009 C++ Standards Committee Mailing - Object Lifetimes and Threads
Monday, 18 May 2009
The May 2009 mailing for the C++ Standards Committee was published a couple of weeks ago. This is a minimal mailing between meetings, and only has a small number of papers.
The primary reason I'm mentioning it is because one of the papers
is concurrency related: N2880:
C++ object lifetime interactions with the threads API by
Hans-J. Boehm and Lawrence Crowl. Hans and Lawrence are concerned
about the implications of thread_local
objects with destructors, and
how you can safely clean up threads if you don't call join()
. The
issue arose during discussion of the proposed async()
function, but is generally applicable.
thread_local
variables and detached threads
Suppose you run a function on a thread for which you want the
return value. You might be tempted to use std::packaged_task<>
and std::unique_future<>
for this; after all it's almost exactly what they're designed for:
#include <thread> #include <future> #include <iostream> int find_the_answer_to_LtUaE(); std::unique_future<int> start_deep_thought() { std::packaged_task<int()> task(find_the_answer_to_LtUaE); std::unique_future<int> future=task.get_future(); std::thread t(std::move(task)); t.detach(); return future; } int main() { std::unique_future<int> the_answer=start_deep_thought(); do_stuff(); std::cout<<"The answer="<<the_answer.get()<<std::endl; }
The call to get()
will wait for the task to finish, but not the
thread. If there are no thread_local
variable
this is not a problem — the thread is detached so the library
will clean up the resources assigned to it automatically. If there
are thread_local
variables (used in
find_the_answer_to_LtUaE()
for example), then this
does cause a problem, because their destructors are not
guaranteed to complete when get()
returns. Consequently, the program may exit before the destructors of
the thread_local
variables have completed, and we have a
race condition.
This race condition is particularly problematic if the thread
accesses any objects of static storage duration, such as global
variables. The program is exiting, so these are being destroyed; if
the thread_local
destructors in the still-running thread
access global variables that have already been destroyed then your
program has undefined behaviour.
This isn't the only problem that Hans and Lawrence discuss —
they also discuss problems with thread_local
and threads
that are reused for multiple tasks — but I think it's the most
important issue.
Solutions?
None of the solutions proposed in the paper are ideal. I
particularly dislike the proposed removal of the detach()
member function from std::thread
. If
you can't detach a thread directly then it makes functions like
start_deep_thought()
much harder to write, and people
will find ways to simulate detached threads another way. Of the
options presented, my preferred choice is to allow registration of a
thread termination handler which is run after all
thread_local
objects have been destroyed. This handler
can then be used to set the value on a future or notify a condition
variable. However, it would make start_deep_thought()
more complicated, as std::packaged_task<>
wouldn't automatically make use of this mechanism unless it was
extended to do so — if it did this every time then it would make
it unusable in other contexts.
If anyone has any suggestions on how to handle the issue, please leave them in the comments below and I'll pass them on to the rest of the committee.
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 left.
March 2009 C++ Standards Committee Mailing - New C++0x Working Paper, Concurrency Changes
Monday, 30 March 2009
The March 2009 mailing for the C++ Standards Committee was published last week. This mailing contains the results of the first round of National Body voting on the C++0x draft, as well as the latest version of the C++0x working draft. This latest draft includes some changes in response to these NB comments, as agreed at the committee meeting at the beginning of March. Some of the changes related to concurrency and the thread library are listed below. The state of all comments (accepted, rejected, or unprocessed) can be found in N2863: C++ CD1 comment status.
The committee is intending to address all the comments (which may include rejecting some, as has already happened) in time to publish a second draft for National Body comments by the end of the year. If there is sufficient consensus on that draft, it will become the C++0x standard, otherwise it will have to undergo another round of revisions.
Concurrency-related Changes
The atomics library has only seen one accepted change so far, and that's a result of US issue 91: a failed compare_exchange operation is only atomic load rather than a read-modify-write operation. This should not have any impact on code that uses atomics, but can enable the implementation to be optimized on some architectures. The details can be seen in LWG issue 1043.
On the other hand, the thread library has seen a couple of accepted changes which will have user-visible consequences. These are:
std::thread
destructor callsstd::terminate()
instead ofdetach()
- Hans Boehm's paper N2082:
A plea to reconsider detach-on-destruction for thread objects, was
reviewed as part of US issue 97. The result is that if you do not
explicitly call
join()
ordetach()
on yourstd::thread
objects before they are destroyed then the library will callstd::terminate()
. This is to ensure that there are no unintentional "dangling threads" with references to local variables. std::thread
andstd::unique_lock
no longer haveswap()
functions that operate on rvalues- This change is in response to US issue 46, and the associated
paper N2844:
Fixing a Safety Problem with Rvalue References: Proposed Wording
(Revision 1), which changes the way the rvalue-references work. In
particular, an rvalue-reference no longer binds to an lvalue. Combined
with the previous change to disallow destroying
std::thread
objects with an associated thread of execution this makes perfect sense: swapping two rvaluestd::thread
objects serves no purpose anyway, and swapping astd::thread
variable with an rvalue would now callstd::terminate()
when the rvalue is destroyed at the end of the expression, if the variable had an associated thread of execution. - The single-argument
std::thread
constructor has been removed - This was UK issue 323. The variadic
std::thread
constructor provides all the necessary functionality.
There are also a few minor concurrency-related changes that have
been approved, mostly along the lines of clarifying the text. There
are a few more which are still under discussion, one of which is quite
significant: UK issue 329. This comment proposes the addition of a new
function std::async()
which will execute a function
asynchronously and return a std::unique_future
which can
be used to obtain the result. Details can be seen under LWG
issue 1043.
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 left.
Rvalue References and Perfect Forwarding in C++0x
Wednesday, 03 December 2008
One of the new features
in C++0x
is the rvalue reference. Whereas the a "normal" lvalue
reference is declared with a single ampersand &
,
an rvalue reference is declared with two
ampersands: &&
. The key difference is of course
that an rvalue reference can bind to an rvalue, whereas a
non-const
lvalue reference cannot. This is primarily used
to support move semantics for expensive-to-copy objects:
class X { std::vector<double> data; public: X(): data(100000) // lots of data {} X(X const& other): // copy constructor data(other.data) // duplicate all that data {} X(X&& other): // move constructor data(std::move(other.data)) // move the data: no copies {} X& operator=(X const& other) // copy-assignment { data=other.data; // copy all the data return *this; } X& operator=(X && other) // move-assignment { data=std::move(other.data); // move the data: no copies return *this; } }; X make_x(); // build an X with some data int main() { X x1; X x2(x1); // copy X x3(std::move(x1)); // move: x1 no longer has any data x1=make_x(); // return value is an rvalue, so move rather than copy }
Though move semantics are powerful, rvalue references offer more than that.
Perfect Forwarding
When you combine rvalue references with function templates you get an interesting interaction: if the type of a function parameter is an rvalue reference to a template type parameter then the type parameter is deduce to be an lvalue reference if an lvalue is passed, and a plain type otherwise. This sounds complicated, so lets look at an example:
template<typename T> void f(T&& t); int main() { X x; f(x); // 1 f(X()); // 2 }
The function template f
meets our criterion above, so
in the call f(x)
at the line marked "1", the template
parameter T
is deduced to be X&
,
whereas in the line marked "2", the supplied parameter is an rvalue
(because it's a temporary), so T
is deduced to
be X
.
Why is this useful? Well, it means that a function template can
pass its arguments through to another function whilst retaining the
lvalue/rvalue nature of the function arguments by
using std::forward
. This is called "perfect
forwarding", avoids excessive copying, and avoids the template
author having to write multiple overloads for lvalue and rvalue
references. Let's look at an example:
void g(X&& t); // A void g(X& t); // B template<typename T> void f(T&& t) { g(std::forward<T>(t)); } void h(X&& t) { g(t); } int main() { X x; f(x); // 1 f(X()); // 2 h(x); h(X()); // 3 }
This time our function f
forwards its argument to a
function g
which is overloaded for lvalue and rvalue
references to an X
object. g
will
therefore accept lvalues and rvalues alike, but overload resolution
will bind to a different function in each case.
At line "1", we pass a named X
object
to f
, so T
is deduced to be an lvalue
reference: X&
, as we saw above. When T
is an lvalue reference, std::forward<T>
is a
no-op: it just returns its argument. We therefore call the overload
of g
that takes an lvalue reference (line B).
At line "2", we pass a temporary to f
,
so T
is just plain X
. In this
case, std::forward<T>(t)
is equivalent
to static_cast<T&&>(t)
: it ensures that
the argument is forwarded as an rvalue reference. This means that
the overload of g
that takes an rvalue reference is
selected (line A).
This is called perfect forwarding because the same
overload of g
is selected as if the same argument was
supplied to g
directly. It is essential for library
features such as std::function
and std::thread
which pass arguments to another (user
supplied) function.
Note that this is unique to template functions: we can't do this
with a non-template function such as h
, since we don't
know whether the supplied argument is an lvalue or an rvalue. Within
a function that takes its arguments as rvalue references, the named
parameter is treated as an lvalue reference. Consequently the call
to g(t)
from h
always calls the lvalue
overload. If we changed the call
to g(std::forward<X>(t))
then it would always
call the rvalue-reference overload. The only way to do this with
"normal" functions is to create two overloads: one for lvalues and
one for rvalues.
Now imagine that we remove the overload of g
for
rvalue references (delete line A). Calling f
with an
rvalue (line 2) will now fail to compile because you can't
call g
with an rvalue. On the other hand, our call
to h
with an rvalue (line 3) will still
compile however, since it always calls the lvalue-reference
overload of g
. This can lead to interesting problems
if g
stores the reference for later use.
Further Reading
For more information, I suggest reading the accepted rvalue reference paper and "A Brief Introduction to Rvalue References", as well as the current C++0x working draft.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: rvalue reference, cplusplus, C++0x, forwarding
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 left.
October 2008 C++ Standards Committee Mailing - New C++0x Working Paper, More Concurrency Papers Approved
Wednesday, 08 October 2008
The October 2008 mailing for the C++ Standards Committee was published today. This is a really important mailing, as it contains the latest edition of the C++0x Working Draft, which was put out as a formal Committee Draft at the September 2008 meeting. This means it is up for formal National Body voting and comments, and could in principle be the text of C++0x. Of course, there are still many issues with the draft and it will not be approved as-is, but it is "feature complete": if a feature is not in this draft it will not be in C++0x. The committee intends to fix the issues and have a final draft ready by this time next year.
Concurrency Papers
As usual, there's a number of concurrency-related papers that have been incorporated into the working draft. Some of these are from this mailing, and some from prior mailings. Let's take a look at each in turn:
- N2752: Proposed Text for Bidirectional Fences
- This paper modifies the wording for the use of fences in C++0x. It
is a new revision of N2731:
Proposed Text for Bidirectional Fences, and is the version voted
into the working paper. Now this paper has been accepted, fences are
no longer tied to specific atomic variables, but are represented by
the free functions
std::atomic_thread_fence()
andstd::atomic_signal_fence()
. This brings C++0x more in line with current CPU instruction sets, where fences are generally separate instructions with no associated object.std::atomic_signal_fence()
just restricts the compiler's freedom to reorder variable accesses, whereasstd::atomic_thread_fence()
will typically also cause the compiler to emit the specific synchronization instructions necessary to enforce the desired memory ordering. - N2782: C++ Data-Dependency Ordering: Function Annotation
- This is a revision of N2643:
C++ Data-Dependency Ordering: Function Annotation, and is the
final version voted in to the working paper. It allows functions to be
annotated with
[[carries_dependency]]
(using the just-accepted attributes proposal) on their parameters and return value. This can allow implementations to better-optimize code that usesstd::memory_order_consume
memory ordering. - N2783: Collected Issues with Atomics
- This paper resolves LWG issues 818, 845, 846 and 864. This rewords
the descriptions of the memory ordering values to make it clear what
they mean, removes the
explicit
qualification on thestd::atomic_xxx
constructors to allow implicit conversion on construction (and thus allow aggregate-style initialization), and adds simple definitions of the constructors for the atomic types (which were omitted by accident). - N2668: Concurrency Modifications to Basic String
- This has been under discussion for a while, but was finally
approved at the September meeting. The changes in this paper ensure
that it is safe for two threads to access the same
std::string
object at the same time, provided they both perform only read operations. They also ensure that copying a string object and then modifying that copy is safe, even if another thread is accessing the original. This essentially disallows copy-on-write implementations since the benefits are now severely limited. - N2748: Strong Compare and Exchange
- This paper was in the previous mailing, and has now been
approved. In the previous working paper, the atomic
compare_exchange
functions were allowed to fail "spuriously" even when the value of the object was equal to the comparand. This allows efficient implementation on a wider variety of platforms than otherwise, but also requires almost all uses ofcompare_exchange
to be put in a loop. Now this paper has been accepted, instead we provide two variants:compare_exchange_weak
andcompare_exchange_strong
. The weak variant allows spurious failure, whereas the strong variant is not allowed to fail spuriously. On architectures which provide the strong variant by default (such as x86) this would remove the need for a loop in some cases. - N2760: Input/Output Library Thread Safety
- This paper clarifies that unsynchronized access to I/O streams
from multiple threads is a data race. For most streams this means the
user is responsible for providing this synchronization. However, for
the standard stream objects (
std::cin
,std::cout
,std::cerr
and friends) such external synchronization is only necessary if the user has calledstd::ios_base::sync_with_stdio(false)
. - N2775: Small library thread-safety revisions
- This short paper clarifies that the standard library functions may only access the data and call the functions that they are specified to do. This makes it easier to identify and eliminate potential data races when using standard library functions.
- N2671: An Asynchronous Future Value: Proposed Wording
- Futures are finally in C++0x! This paper from the June 2008
mailing gives us
std::unique_future<>
,std::shared_future<>
andstd::promise<>
, which can be used for transferring the results of operations safely between threads. - N2709: Packaging Tasks for Asynchronous Execution
- Packaged Tasks are also in C++0x! This is my paper from the July
2008 mailing, which is the counterpart to N2671. A
std::packaged_task<F>
is very similar to astd::function<F>
except that rather than returning the result directly when it is invoked, the result is stored in the associated futures. This makes it easy to spawn functions with return values on threads, and provides a building block for thread pools.
Other Changes
The biggest change to the C++0x working paper is of course the acceptance of Concepts. There necessary changes are spread over a staggering 14 Concepts-related papers, all of which were voted in to the working draft at the September 2008 meeting.
C++0x now also has support for user-defined literals (N2765:
User-defined Literals (aka. Extensible Literals (revision 5))),
for default values of non-static
data members to be
defined in the class
definition (N2756:
Non-static data member initializers), and forward declaration of
enum
s (N2764:
Forward declaration of enumerations (rev. 3)).
Get Involved: Comment on the C++0x Draft
Please read the latest C++0x Working Draft and comment on it. If you post comments on this blog entry I'll see that the committee gets to see them, but I strongly urge you to get involved with your National Body: the only changes allowed to C++0x now are in response to official National Body comments. If you're in the UK, contact me and I'll put you in touch with the relevant people on the BSI panel.
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 left.
C++0x Draft and Concurrency Papers in the August 2008 Mailing
Thursday, 28 August 2008
Yesterday, the August 2008 C++ Standards Committee Mailing was published. This features a new Working Draft for C++0x, as well as quite a few other papers.
Thread-local storage
This draft incorporates N2659:
Thread-Local Storage, which was voted in at the June committee
meeting. This introduces a new keyword: thread_local
which can be used to indicate that each thread will have its own copy
of an object which would otherwise have static storage duration.
thread_local int global; thread_local std::string constructors_allowed; void foo() { struct my_class{}; static thread_local my_class block_scope_static; }
As the example above shows, objects with constructors and
destructors can be declared thread_local
. The constructor
is called (or other initialization done) before the first use of such
an object by a given thread. If the object is used on a given thread
then it is destroyed (and its destructor run) at thread exit. This is
a change from most common pre-C++0x implementations, which exclude
objects with constructors and destructors.
Additional concurrency papers
This mailing contains several papers related to concurrency and multithreading in C++0x. Some are just rationale or comments, whilst others are proposals which may well therefore be voted into the working draft at the September meeting. The papers are listed in numerical order.
- N2731: Proposed Text for Bidirectional Fences
- This is a revised version of N2633:
Improved support for bidirectional fences,
which incorporates naming changes requested by the committee at the
June meeting, along with some modifications to the memory model. In
particular, read-modify-write operations (such as
exchange
orfetch_add
) that use thememory_order_relaxed
ordering can now feature as part of a release sequence, thus increasing the possibilities for usingmemory_order_relaxed
operations in lock-free code. Also, the definition of how fences that usememory_order_seq_cst
interact with othermemory_order_seq_cst
operations has been clarified. - N2744: Comments on Asynchronous Future Value Proposal
- This paper is a critique of N2671:
An Asynchronous Future Value: Proposed Wording. In short, the
suggestions are:
- that
shared_future<T>::get()
should return by value rather than by const reference; - that
promise
objects are copyable; - and that the
promise
functions for setting the value and exception be overloaded with versions that return an error code rather than throwing an exception on failure.
- that
- N2745: Example POWER Implementation for C/C++ Memory Model
- This paper discusses how the C++0x memory model and atomic operations can be implemented on systems based on the POWER architecture. As a consequence, this also shows how the different memory orderings can affect the actual generated code for atomic operations.
- N2746: Rationale for the C++ working paper definition of "memory location"
- This paper is exactly what it says: a rationale for the definition
of "memory location". Basically, it discusses the reasons why every
object (even those of type
char
) is a separate memory location, even though this therefore requires that memory be byte-addressable, and restricts optimizations on some architectures. - N2748: Strong Compare and Exchange
- In the current working paper, the atomic
compare_exchange
functions are allowed to fail "spuriously" even when the value of the object was equal to the comparand. This allows efficient implementation on a wider variety of platforms than otherwise, but also requires almost all uses ofcompare_exchange
to be put in a loop. This paper proposes that instead we provide two variants:compare_exchange_weak
andcompare_exchange_strong
. The weak variant would be the same as the current version, whereas the strong variant would not be allowed to fail spuriously. On architectures which provide the strong variant by default (such as x86) this would remove the need for a loop in some cases.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: c++0x, 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 left.
July 2008 C++ Standards Committee Mailing Published
Wednesday, 30 July 2008
The July 2008 mailing for the C++ Standards
Committee was published today. Primarily this is just an update on the "state of evolution" papers, and the issue
lists. However, there are a couple of new and revised papers. Amongst them is my revised paper on packaged_task
: N2709: Packaging Tasks for Asynchronous Execution.
As I mentioned when the most recent C++0x draft
was published, futures are still under discussion,
and the LWG requested that packaged_task
be moved to a separate paper, with a few minor changes. N2709 is this separate paper. Hopefully the LWG will
approve this paper at the September meeting of the C++ committee in San Francisco; if they don't, then packaged_task
will join the long list of proposals that have missed the boat for C++0x.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++0x, C++, standards
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 left.
C++ Concurrency Papers Still Under Discussion
Monday, 07 July 2008
Last week I wrote about the new working draft of the C++0x standard and the newly-accepted concurrency papers, but I didn't mention the papers still under discussion. There's a few of those, listed below. The committee intends to publish a formal Committee Draft of the C++0x Standard at the end of the September meeting, so anything not voted into the WP at that meeting has missed the boat (though of course defects will still be fixed).
- N2671: An Asynchronous Future Value: Proposed Wording
- For those of you who've been following my postings about asynchronous
future values for C++, this is the latest proposal on
futures. Though it was discussed at the June meeting, the LWG didn't
feel it was ready to be voted in to the working draft yet. At the request of
the LWG,
packaged_task
has been removed; I should have a separate proposal for that ready before the next meeting. - N2668: Concurrency Modifications to Basic String
- Yes, I listed this as approved last week, but I misread the
minutes of the votes: it is still under discussion. The changes in
this paper ensure that it is safe for two threads to access the same
std::string
object at the same time, provided they both perform only read operations. They also ensure that copying a string object and then modifying that copy is safe, even if another thread is accessing the original. This essentially disallows copy-on-write implementations since the benefits are now severely limited. - N2633: Improved support for bidirectional fences
- This paper aims to simplify and improve the support for fences
(also known as memory barriers) when writing code using the new atomic
types. As the paper points out, the current
atomic_variable.fence(memory_ordering)
semantics can mean that compilers have to issue stronger-than-necessary fences in many cases. By making the fences free functions that are not tied to an individual variable, they will map much better to the underlying instructions, and should lead to clearer (and more optimal) code. - N2643: C++ Data-Dependency Ordering: Function Annotation
- This paper is a counterpart to N2664:
C++ Data-Dependency Ordering: Atomics and Memory Model, and
extends the list of cases where dependencies are carried by allowing
you to annotate functions. The new style
[[annotation syntax]]
is used to indicate which parameters carry a dependency into a function, and whether or not the return type carries a dependency to the call site.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: C++, concurrency, C++0x
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 left.
New C++ Working Draft and Concurrency Papers Now Available
Friday, 04 July 2008
The post-meeting mailing following June's C++ Standards committee meeting in France is now available. This includes a new Working Draft for the C++0x standard, and a few concurrency-related papers.
From a concurrency point of view, there are several papers of interest. Firstly, a few have been accepted into the working draft, notably:
- N2661: A Foundation to Sleep On
- This paper provides a generalised time
point and duration library, which is used by the thread functions that
take times or durations. These have been updated to use these new
types and renamed to make their purpose clearer: functions that wait
for a duration are now called
xxx_for
, and take a value of typestd::chrono::duration<Rep,Period>
, whereas those that take absolute time points are now calledxxx_until
and take a value of typestd::chrono::time_point<Clock,Duration>
. - N2668: Concurrency Modifications to Basic String
- Update: This paper has not actually been approved, I was
mistaken. Though the majority of the committee were in favour, there
was not consensus, so this paper will be discussed at a future
meeting. Thanks to Herb Sutter for
picking me up on this.
The changes in this paper ensure that it is safe for two threads to access the samestd::string
object at the same time, provided they both perform only read operations. They also ensure that copying a string object and then modifying that copy is safe, even if another thread is accessing the original. This essentially disallows copy-on-write implementations since the benefits are now severely limited. - N2660: Dynamic Initialization and Destruction with Concurrency
- With the changes from this paper, if an application uses multiple threads then the initialization and destruction of objects with static storage duration (such as global variables) may run concurrently on separate threads. This can provide faster start-up and shut-down times for an application, but it can also introduce the possibility of race conditions where none existed previously. If you use threads in your application, it is now even more important to check the initialization order of objects with static storage duration.
- N2514: Implicit Conversion Operators for Atomics
- With this change, the atomic types such as
std::atomic_int
are implicitly convertible to their corresponding fundamental types. This means, for example, that:std::atomic_int x; int y=x;
is well-formed where it wasn't previously. The implicit conversions are equivalent to calling theload()
member function, and havememory_order_seq_cst
ordering semantics. - N2674: Shared_ptr atomic access, revision 1
- This paper introduces a new set of overloads of the free functions
for atomic operations (such as
atomic_load
andatomic_store
), which operate on instances ofstd::shared_ptr<>
. This allows one thread to read an instance ofstd::shared_ptr
whilst another thread is modifying that same instance if they both use the new atomic functions.
This paper also renamesatomic_swap
operations toatomic_exchange
(and likewise foratomic_compare_swap
and the corresponding member functions) for all atomic types, in order to avoid confusion with other types that provideswap
functions. The atomic exchange operations only alter the value of a single object, replacing the old value with a new one, they do not exchange the values of two objects in the way thatstd::swap
does. - N2664: C++ Data-Dependency Ordering: Atomics and Memory Model
- With the adoption of this paper the memory model gets a new
ordering option:
memory_order_consume
. This is a limited form ofmemory_order_acquire
which allows for data-dependent ordering. If a thread usesmemory_order_consume
, then it is not guaranteed to see modifications to other variables made by the thread that performed the releasing operation unless those variables are accessed in conjunction with the consumed variable. This means, for example, that member variables of an object are visible if the consumed value is a pointer to that object, but that values of independent objects are not necessarily visible. This allows the compiler to perform some optimizations that are forbidden bymemory_order_acquire
, and reduces the synchronization overhead on some hardware architectures. - N2678: Error Handling Specification for Chapter 30 (Threads)
- This paper brings the exceptions thrown by the thread under the
new
system_error
umbrella, with corresponding error codes and error categories. - N2669: Thread-Safety in the Standard Library (Rev 2)
- Now the standard supports threads, we need to say which standard library operations are thread-safe, and which are not. This paper basically says that non-modifying operations on the same object are safe, and any operations on separate objects are also safe. Also, separate threads may call the same library functions on separate objects without problems. As you might expect, concurrent modifications to the same object are data races and undefined behaviour.
The committee also voted to include N2659:
Thread-Local Storage in C++0x, but it doesn't appear to be in the
current draft. This paper introduces the thread_local
keyword to indicate that each thread should have its own copy of a
given object.
Finally, N2657: Local and Unnamed Types as Template Arguments has been incorporated in the working paper. Though this isn't directly concurrency related, it is something I've been campaigning for since N1427 back in 2003.
Apart from N2657, I've only listed the concurrency changes: check out the Working Draft for the C++0x standard, and the State of C++ Evolution for more details on the changes.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Tags: concurrency, c++
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 left.
Design and Content Copyright © 2005-2024 Just Software Solutions Ltd. All rights reserved. | Privacy Policy