completed threading/atomic

This commit is contained in:
Frank B. Brokken 2014-10-13 17:16:02 +02:00
parent 9c2bca6d14
commit 338dbff64a
7 changed files with 284 additions and 91 deletions

View file

@ -13,7 +13,7 @@ to be rewritten to have it accepted by the compiler:
If promotions are welcome, how can we change the arithmetic operator
function templates so that promotions are performed? With promotions the
arguments of the operator functions may be of any type, at least one of them
must be of the class type offering the matching arithmetic assignment
must be of the class type offering the matching compound assignment
operator. But when designing the function template we can't say which of the
two operands has that class type. So we have to specify two template
types parameters for the two parameters of the operator functions. The

View file

@ -18,7 +18,7 @@ object = 120; // same as object = 'x'
)
it() addition:
quote(the arithmetic additive assignment operator and the addition
operator add text to a tt(string) object. The arithmetic assignment operator
operator add text to a tt(string) object. The compound assignment operator
returns its left-hand side operand, the addition operator returns its result
in a temporary string object. When using the addition operator either the
left-hand side operand or the right-hand side operand must be a

View file

@ -67,7 +67,6 @@ includefile(threading/events)
sect(Atomic actions: mutexes not required)
includefile(threading/atomic)
COMMENT( REMOVE THE COMMENT IN THIS FILE)
lsect(FUTURE)(Asynchronous return objects: the class `std::future')
includefile(threading/future)
@ -78,12 +77,19 @@ sect(Shared asynchronous return objects: the class `std::shared_future')
includefile(threading/sharedfuture)
lsect(ASYNC)(Starting a new thread: the function `std::async')
includefile(threading/async)
COMMENT()
lsect(PACKAGE)
(Preparing a task for execution: the class `std::packaged_task')
includefile(threading/packagedtask)
lsect(PROMISE)(The class `std::promise')
includefile(threading/promise)
sect(An example: multi-threaded compilations)
includefile(threading/compilations)

View file

@ -31,7 +31,8 @@ type names are available. E.g, instead of tt(std::atomic<unsigned short>) the
type tt(std::atomic_ushort) can be used. Refer to the tt(atomic) header file
for a complete list of alternate names.
If tt(Trivial) is a user-defined trivial type then tt(std::atomic<Trivial>)
If tt(Trivial) is a user-defined trivial type then
hi(atomic<Trivial>)tt(std::atomic<Trivial>)
defines an atomic variant of tt(Trivial): such a type does not require
a separate tt(mutex) to synchronize access by multiple threads.
@ -40,25 +41,227 @@ copied or assigned to each other. However, they can be initialized by values
of type tt(Type), and values of type tt(Type) can also directly be assigned to
tt(std::atomic<Type>) objects.
The class tt(std::atomic<Type>) defines the following members:
The class tt(std::atomic<Type>) provides several public members, listed
below. Non-member (free) functions operating on tt(atomic<Type>) objects
are also available.
The tt(std::memory_order) enumeration defines the following symbolic
constants, which are used to specify ordering constraints of atomic operations:
itemization(
itt(memory_order_acq_rel:) the operation must be a read-modify-write
operation, combining tt(memory_order_acquire) and
tt(memory_order_release);
itt(memory_order_acquire:) the operation is an acquire operation. It
synchronizes with a release operation that wrote the same memory
location;
itt(memory_order_consume:) the operation is a consume operation on the
involved memory location;
itt(memory_order_relaxed:) no ordering constraints are provided by the
operation;
itt(memory_order_release:) the operation is a release operation. It
synchronizes with acquire operations on the same location;
itt(memory_order_sec_cst:) the default memory order specification for all
operations. Memmory storing operations use tt(memory_order_release),
memory load operations use tt(memory_order_acquire), and
read-modify-write operations use tt(memory_order_acq_rel).
)
The memory order cannot be specified for the overloaded operators provided by
tt(atomic<Type>). Otherwise, most tt(atomic) member functions may also be
given a final tt(memory_order) argument. Where this is not available it is
explictly mentioned at the function's description.
Here are the standard available tt(std::atomic<Type>) member functions:
itemization(
ithtq(compare_exchange_strong)(bool compare_exchange_strong(Type
&oldValue, Type newValue) noexcept)
()
&currentValue, Type newValue) noexcept)
(The value in the atomic object is compared to tt(newValue) using
byte-wise comparisons. If equal tt(true) is returned, and
tt(newValue) is stored in the atomic object; if unequal tt(false) is
returned and the object's current value is stored in
tt(currentValue);)
ithtq(compare_exchange_weak)(bool compare_exchange_weak(Type &oldValue,
Type newValue) noexcept)
()
ithtq(exchange)(Type exchange(Type) noexcept)
()
(The value in the atomic object is compared to tt(newValue) using
byte-wise comparisons. If equal tt(true) is returned, and tt(newValue)
is stored in the atomic object; if unequal, or tt(newValue) cannot be
atomically assigned to the current object tt(false) is returned and
the object's current value is stored in tt(currentValue);)
ithtq(exchange)(Type exchange(Type newValue) noexcept)
(The object's current value is returned, and tt(newValue) is assigned
to the current object;)
ithtq(is_lock_free)(bool is_lock_free() const noexept)
()
(If the operations on the current object can be performed lock-free
tt(true) is returned, otherwise tt(false).
This member has no tt(memory_order) parameter;)
ithtq(load)(Type load() const noexcept)
()
(The object's value is returned;)
ithtq(operator Type() const noexcept)
()
ithtq(store)(void store(Type) noexcept)
()
(The object's value is returned;)
ithtq(store)(void store(Type newValue) noexcept)
(tt(NewValue) is assigned to the current object. Note that the standard
assignment operator can also be used.)
)
In addition to the above members, integral atomic types `tt(Integral)'
(essentially the atomic variants of all built-in integral types) also offer
the following member functions:
itemization(
ithtq(fetch_add)(Integral fetch_add(Integral value) noexcept)
(tt(Value) is added to the object's value, and the object's
value at the time of the call is returned;)
ithtq(fetch_sub)(Integral fetch_sub(Integral value) noexcept)
(tt(Value) is subtracted from the object's value, and the object's
value at the time of the call is returned;)
ithtq(fetch_and)(Integral fetch_and(Integral mask) noexcept)
(The tt(bit-and) operator is applied to the object's value and
tt(mask), assigning the resulting value to the currrent object. The
object's value at the time of the call is returned;)
ithtq(fetch_|=)(Integral fetch_|=(Integral mask) noexcept)
(The tt(bit-or) operator is applied to the object's value and tt(mask),
assigning the resulting value to the currrent object. The object's
value at the time of the call is returned;)
ithtq(fetch_^=)(Integral fetch_^=(Integral mask) noexcept)
(The tt(bit-xor) operator is applied to the object's value and
tt(mask), assigning the resulting value to the currrent object. The
object's value at the time of the call is returned;)
ithtq(operator++)(Integral operator++() noexcept)
(The prefix increment operator, returning object's new value;)
ithtq(operator++)(Integral operator++(int) noexcept)
(The postfix increment operator, returning the object's value before it
was incremented;)
ithtq(operator--)(Integral operator--() noexcept)
(The prefix decrement operator, returning object's new value;)
ithtq(operator--)(Integral operator--(int) noexcept)
(The postfix decrement operator, returning the object's value before it
was decremented;)
ithtq(operator+=)(Integral operator+=(Integral value) noexcept)
(tt(Value) is added to the object's current value and the object's
new value is returned;)
ithtq(operator-=)(Integral operator-=(Integral value) noexcept)
(tt(Value) is subtracted from the object's current value and the
object's new value is returned;)
ithtq(operator&=)(Integral operator&=(Integral mask) noexcept)
(The tt(bit-and) operator is applied to the object's current value and
tt(mask), assigning the resulting value to the currrent object. The
object's new value is returned;)
ithtq(operator|=)(Integral operator|=(Integral mask) noexcept)
(The tt(bit-or) operator is applied to the object's current value and
tt(mask), assigning the resulting value to the currrent object. The
object's new value is returned;)
ithtq(operator^=)(Integral operator^=(Integral mask) noexcept)
(The tt(bit-xor) operator is applied to the object's current value and
tt(mask), assigning the resulting value to the currrent object. The
object's new value is returned;)
)
Some of the free member functions have names ending in tt(_explicit). The
tt(_explicit) functions define an additional ti(memory_order order) parameter,
which is not available for the non-tt(_explicit) functions (e.g.,
tt(atomic_load(atomic<Type> *ptr)) and tt(atomic_load_explicit(atomic<Type>
*ptr, memory_order order)))
Here ar the free functions that are available for all atomic types:
itemization(
ithtq(atomic_compare_exchange_strong(_explicit))(bool
std::atomic_compare_exchange_strong(_explicit)(std::atomic<Type> *ptr,
Type *oldValue, Type newValue) noexept)
(returns tt(ptr->compare_exchange_strong(*oldValue, newValue));)
ithtq(atomic_compare_exchange_weak(_explicit))(bool
std::atomic_compare_exchange_weak(_explicit)(std::atomic<Type> *ptr,
Type *oldValue, Type newValue) noexept)
(returns tt(ptr->compare_exchange_weak(*oldValue, newValue));)
ithtq(atomic_exchange(_explicit))(Type
std::atomic_exchange(_explicit)(std::atomic<Type> *ptr, Type newValue)
noexept)
(returns tt(ptr->exchange(newValue));)
ithtq(atomic_init)(void std::atomic_init(std::atomic<Type> *ptr, Type
init) noexept)
(Stores tt(init) em(non)-atomically in tt(*ptr). The object pointed to
by tt(ptr) must have been default constructed, and as yet no member
functions must have been called for it.
This function has no tt(memory_order) parameter;)
ithtq(atomic_is_lock_free)(bool std::atomic_is_lock_free(std::atomic<Type>
const *ptr) noexept)
(returns tt(ptr->is_lock_free()).
This function has no tt(memory_order) parameter;)
ithtq(atomic_load(_explicit))(Type
std::atomic_load(_explicit)(std::atomic<Type> *ptr) noexept)
(returns tt(ptr->load());)
ithtq(atomic_store(_explicit))(void
std::atomic_store(_explicit)(std::atomic<Type> *ptr, Type value)
noexept)
(calls tt(ptr->store(value)).)
)
In addition to the abovementioned free functions tt(atomic<Integral>) types
also offer the following free member functions:
itemization(
ithtq(atomic_fetch_add(_explicit))(Integral
std::atomic_fetch_add(_explicit)(std::atomic<Integral> *ptr, Integral
value) noexcept)
(returns tt(ptr->fetch_add(value));)
ithtq(atomic_fetch_sub(_explicit))(Integral
std::atomic_fetch_sub(_explicit)(std::atomic<Integral> *ptr, Integral
value) noexcept)
(returns tt(ptr->fetch_sub(value));)
ithtq(atomic_fetch_and)(Integral
std::atomic_fetch_and(_explicit)(std::atomic<Integral> *ptr, Integral
mask) noexcept)
(returns tt(ptr->fetch_and(value));)
ithtq(atomic_fetch_or)(Integral
std::atomic_fetch_or(_explicit)(std::atomic<Integral> *ptr, Integral
mask) noexcept)
(returns tt(ptr->fetch_or(value));)
ithtq(atomic_fetch_xor)(Integral
std::atomic_fetch_xor(_explicit)(std::atomic<Integral> *ptr, Integral
mask) noexcept)
(returns tt(ptr->fetch_xor(mask)).)
)

View file

@ -76,7 +76,7 @@ In addition, tt(duration) has these members:
quote(Duration objects may be added, or subtracted, and they may be
multiplied and divided by a numeric value. They also support the modulo
operator, using an integral constant for its right-hand side operand. The
binary arithmetic and the binary arithmetic assignment operators are also
binary arithmetic and the binary compound assignment operators are also
available.)
ithtq(count)(constexpr Value count() const)
@ -99,7 +99,7 @@ representing+linebreak() tt(numeric_limits<Rep>::max()).)
Different tt(duration) types may be combined, unless precision would be
lost. When the binary arithmetic operators are used the resulting tt(duration)
uses the finer of the two granularities. When the binary arithmetic assignment
uses the finer of the two granularities. When the binary compound assignment
operator is used the granulatity of the left-hand side operand must at least
be equal to the granularity of the right-hand side operand, or a compilation
error is issued. E.g.,

View file

@ -27,16 +27,6 @@ an exception. In that case the tt(future) object catches the exception,
rethrowing it when its return value (i.e., the value returned by the
asynchronously executed task) is requested.
COMMENT(
By default a tt(future) object has no shared state. A tt(future) object
containing a shared state can be created by members of asynchronous providers
(such as a tt(std::promise) (cf. section ref(PROMISE)), or by the move
constructor. In these cases it shares its shared state with the original
asynchronous provider.
END)
In this section the members of the class template tt(future) are
described. tt(Future) objects are commonly initialized using anonymous
tt(future) objects returned by the factory function tt(std::async) or by the
@ -55,16 +45,15 @@ strongly typed enumeration tt(std::future_errc), covered in the next section.
The class tt(future) has the following constructors:
itemization(
itt(future())
quote(The default constructor constructs an tt(future) object that
does not refer to shared results. Its tt(valid) member returns
tt(false).)
ittq(future())
(The default constructor constructs an tt(future) object that does not
refer to shared results. Its tt(valid) member returns tt(false).)
itt(future(future &&tmp) noexcept)
quote (The move constructor is available. Its tt(valid) member
returns what tt(tmp.valid()) would haved returned prior to the
constructor invocation. After calling the move constructor
tt(tmp.valid()) returns tt(false).)
ittq(future(future &&tmp) noexcept)
(The move constructor is available. Its tt(valid) member returns what
tt(tmp.valid()) would haved returned prior to the constructor
invocation. After calling the move constructor tt(tmp.valid()) returns
tt(false).)
)
The class tt(future) does not offer a copy constructor or overloaded
assignment operator.
@ -77,53 +66,49 @@ of the class tt(shared_future)).
tt(Std::future) provides the following members:
itemization(
itt(future &operator=(future &&tmp))
quote(The move assignment operator grabs the information from the
tt(tmp) object; following this, tt(tmp.valid()) returns
tt(false).)
ittq(future &operator=(future &&tmp))
(The move assignment operator grabs the information from the tt(tmp)
object; following this, tt(tmp.valid()) returns tt(false).)
itt(std::shared_future<ResultType> share() &&)
quote(This member turns an r-value reference to a
tt(future<ResultType>) into a tt(std::shared_future<ResultType>)
(see section ref(SHAREDFUTURE)). After calling this function, the
tt(future's valid) member returns tt(false).)
ittq(std::shared_future<ResultType> share() &&)
(This member turns an r-value reference to a tt(future<ResultType>)
into a tt(std::shared_future<ResultType>) (see section
ref(SHAREDFUTURE)). After calling this function, the tt(future's
valid) member returns tt(false).)
itt(ResultType get())
quote(This member first calls the member tt(wait) (see below), after
which the results produced by the associated asynchronoust task
arereturned. With tt(future<Type>) specifications the returned
value is the moved shared value if tt(Type) supports move
assignment, otherwise a copy is returned. With tt(future<Type &>)
specifications a tt(Type &) is returned, with tt(future<void>)
specifications nothing is returned. If the shared value is an
exception, it is thrown instead of returned. After calling this
member the tt(future) object's tt(valid) member returns
tt(false).)
ittq(ResultType get())
(This member first calls the member tt(wait) (see below), after which
the results produced by the associated asynchronoust task
arereturned. With tt(future<Type>) specifications the returned value
is the moved shared value if tt(Type) supports move assignment,
otherwise a copy is returned. With tt(future<Type &>) specifications
a tt(Type &) is returned, with tt(future<void>) specifications nothing
is returned. If the shared value is an exception, it is thrown instead
of returned. After calling this member the tt(future) object's
tt(valid) member returns tt(false).)
itt(bool valid() const)
quote(
Returns tt(true) if the (tt(future)) object for which tt(valid) is called
refers to an object returned by an asynchronous task. If tt(valid)
returns tt(false), the tt(future) object exists, but in addition to
tt(valid) only its destructor and move constructor can safely be
called. When other members are called while tt(valid) returns tt(false) a
hi(future_error)tt(std::future_error) exception is thrown (having the
value hi(no_state)tt(future_errc::no_state)).)
ittq(bool valid() const)
(Returns tt(true) if the (tt(future)) object for which tt(valid) is
called refers to an object returned by an asynchronous task. If
tt(valid) returns tt(false), the tt(future) object exists, but in
addition to tt(valid) only its destructor and move constructor can
safely be called. When other members are called while tt(valid)
returns tt(false) a hi(future_error)tt(std::future_error) exception is
thrown (having the value hi(no_state)tt(future_errc::no_state)).)
itt(void wait() const)
quote(This member blocks until the results produced by
the associated asynchronous task are available.)
ittq(void wait() const)
(This member blocks until the results produced by the associated
asynchronous task are available.)
COMMENT(future_status?)
itt(future_status wait_for(chrono::duration<Rep, Period> const &rel_time)
const)
quote(This member template derives the template types tt(Rep) and
tt(Period) from the actually specified duration (cf. section
ref(DURATION)). If the results contain a deferred function nothing
happens. Otherwise tt(wait_for) blocks
ittq(std::future_status wait_for(chrono::duration<Rep, Period> const
&rel_time) const)
(This member template derives the template types tt(Rep) and tt(Period)
from the actually specified duration (cf. section ref(DURATION)). If
the results contain a deferred function nothing happens. Otherwise
tt(wait_for) blocks
COMMENT((30.6.8))
until the results are available or until the amount of time
specified by tt(rel_time) has expired. Possible return values are:
until the results are available or until the amount of time
specified by tt(rel_time) has expired. Possible return values are:
itemization(
itt(future_status::deferred) if the results contains a
deferred function;
@ -132,14 +117,14 @@ COMMENT((30.6.8))
the amount of time specified by tt(rel_time) has expired.
))
itt(future_status wait_until(chrono::time_point<Clock, Duration> const
ittq(future_status wait_until(chrono::time_point<Clock, Duration> const
&abs_time) const)
quote(This member template derives the template types tt(Clock) and
tt(Duration) from the actually specified tt(abs_time) (cf. section
ref(TIMEPOINT)). If the results contain a deferred function
nothing happens. Otherwise tt(wait_until) blocks until the results
are available or until the point in time specified by
tt(abs_time) has expired. Possible return values are:
(This member template derives the template types tt(Clock) and
tt(Duration) from the actually specified tt(abs_time) (cf. section
ref(TIMEPOINT)). If the results contain a deferred function nothing
happens. Otherwise tt(wait_until) blocks until the results are
available or until the point in time specified by tt(abs_time) has
expired. Possible return values are:
itemization(
itt(future_status::deferred) if the results contain a
deferred function;

View file

@ -1,15 +1,14 @@
The class template hi(packaged_task)tt(std::packaged_task) allows a thread to
package a function or functor, which is then passed to a second thread for
execution as separate sub-thread, allowing the first thread to retrieve the
sub-thread's results after it has completed.
package a function or functor, which is then passed to another thread, which
calls the function, passing it its arguments (if any). Following the
function's call the packaged task's future is ready, allowing the first thread
to access the results produced by the function. Thus, functions and the
results of function calls can be transferred between threads.
Before using the class template tt(packaged_task) the tthi(future) header file
must be included.
When the packaged_task object is invoked, its stored task is invoked and the
result (whether normal or exceptional) stored in the shared state. Any futures
Any futures
that share the shared state will then be able to access the stored result.
template<class> class packaged_task; // undefined