Cannot construct tuple from atomic object in C++ - c++

I am new to atomic in C++ and trying to make a tuple from atomic objects. I am getting a compile time error and I do not understand why. How can I resolve the error?
Created this test program
int main()
{
std::atomic<double> a1{0};
std::atomic<double> a2{0};
std::atomic<double> a3{0};
// Parallel processing
ParallelFor(...) {
// update atomic variables.
}
std::make_tuple(a1,a2,a3);
return 0;
}
Compile time error:
In instantiation of 'constexpr std::tuple<typename std::__decay_and_strip<_Elements>::__type ...> std::make_tuple(_Elements&& ...) [with _Elements = {std::atomic<double>&, std::atomic<double>&, std::atomic<double>&}]':
progatomic.cpp:17:26: required from here
error: no matching function for call to 'std::tuple<std::atomic<double>, std::atomic<double>, std::atomic<double> >::tuple(std::atomic<double>&, std::atomic<double>&, std::atomic<double>&)'
return __result_type(std::forward<_Elements>(__args)...);
Thanks

The code has two rules applied that are causing the problem:
Type inferencing: You're using std::make_tuple with type-inference, so it's trying to make a tuple templated on the type of the arguments (std::tuple<std::atomic<double>, std::atomic<double>, std::atomic<double>>), copying from the arguments
Non-copyable types: std::atomic is non-copyable
There are at least three different ways to fix this:
If you want a tuple of references to the original std::atomics, use std::tie, e.g. std::tie(a1, a2, a3). No actual data is read from the atomics, so you won't get any complaints, but the tuple will now contain references to std::atomic<double>s that may keep changing.
If you want a tuple of the values currently in the atomics (which will be extracted in an unspecified order, since C++ makes no guarantees on the order in which arguments are evaluated, and therefore you can't guarantee any particular ordering of results if another thread is still modifying them), do one of two things so std::make_tuple knows it's making copies of the actual double values, not the atomics themselves, either:
Explicitly load from the variables: std::make_tuple(a1.load(), a2.load(), a3.load()). For efficiency, since sequential consistency can't actually guarantee the order the arguments are loaded in, you might want to relax the memory ordering requirements explicitly, with std::make_tuple(a1.load(std::memory_order_acquire), a2.load(std::memory_order_acquire), a3.load(std::memory_order_acquire)), or even std::memory_order_relaxed instead. Technically, if the values were stored without std::memory_order_release or stronger, dropping to acquire might allow you to see inconsistent state for non-atomics, but if that's an issue, you could use:
std::make_tuple(a1.load(std::memory_order_relaxed), a2.load(std::memory_order_relaxed), a3.load(std::memory_order_relaxed));
std::atomic_thread_fence(std::memory_order_seq_cst);
to get the best of both worlds; no wasted work per load, just a single fence to guarantee nothing written prior to those loads is missed when non-atomics are read afterwards.
Explicitly template make_tuple so it implicitly casts to the underlying value type, rather than inferring std::atomic<double>: std::make_tuple<double, double, double>(a1, a2, a3) (downside: Since the load is now implicit, you can't relax the memory ordering; three memory fences are going to be involved)
The two approaches are fixing one of the two issues from above, either removing type inference through explicit templating (preserving implicit loads), or removing copying through explicit loads that convert to a copyable type (preserving implicit templating). Either one (or both) would solve the problem, because the problem only occurs when both type-inferencing and non-copyable types are involved.

Related

What trait makes uninitialized_copy(_n) sustituable by copy(_n)?

I am trying to understand the meaning of the types properties and supported operations, https://en.cppreference.com/w/cpp/types .
I have a library that implements in terms of low level functions things similar to std::copy_n, of course I would have to implement uninitialized_copy as well, but for many of the types, that are in some sense trivial, I don't want to repeat code and delegate one to the other.
What property makes uninitialized_copy(_n) semantically substitutable by copy(_n)?
My guess is that it is std::is_trivially_default_constructible<T>::value, but I am not sure.
The justification is that if something is trivially default constructible I can skip the initialization before the assignment.
(Initially I though it could be std::is_trivially_assignable<TSource, T>::value)
Of course I could play safe and ask for std::is_trivial<T>::value, but I want to be more targeted.
I know there are could be Machiavellian or misleading definitions of these traits, but suppose I want to trust them.
Example code:
template<class... As, class... Bs>
auto uninitialized_copy_n(
my_iterator<As...> first, Size count,
my_iterator<Bs...> d_first
)-> my_iterator<Bs...> {
using T1 = typename my_iterator<As...>::value_type;
using T2 = typename my_iterator<Bs...>::value_type;
if constexpr(std::is_trivially_constructible<T2>::value){
return copy_n(first, count, d_first);
}
... another implementation or abort
}
To replace uninitialized_copy with copy, the two actions must be equivalent:
uninitialized_copy: construct a new object of type Destination from an object of type Source
copy: assume an object of type Destination exists and assign to it from an object of type Source
One must put sufficient requirements on the type such that the destination object exists and that construction and assignment give the same value.
is_trivially_default_constructible is neither necessary nor sufficient to assume an object exists at a memory location. Instead, the destination type must be an implicit lifetime type. That is not a recursive condition, so we must require the type be an implicit lifetime type, and recursively all members or subobjects are implicit lifetime types.
For example, scalars or classes with trivial default constructor and trivial destructor will work.
Secondly, we need construction and assignment to give the same result. This is impossible if these operations aren't trivial. But in C++, the value of an object is only guaranteed to be unchanged by such operations for trivially copyable types, which tie the value to the representation. Therefore, we probably want the destination to be trivially copyable.
This gives us:
std::is_trivially_default_constructible_v<Destination>
std::is_trivially_destructible_v<Destination>
std::is_trivially_constructible_v<Destination, const Source&>
std::is_trivially_assignable_v<Destination&, const Source&>
std::is_trivially_copyable_v<Destination>
This simplifies to:
std::is_trivial_v<Destination>
std::is_trivially_constructible_v<Destination, const Source&>
std::is_trivially_assignable_v<Destination&, const Source&>
Note that libstdc++ requires both types to be trivial and the Destination assignable and constructible from the Source. The comment references a slightly different condition on the ranges algorithm instead.
The libstdc++ requirement has observable differences. See this example. value should be 1 (from construction) but is being populated with 2 (from assignment). I cannot find any license given to implementations to differ in this way.
The libstdc++ logic was recently found to be buggy and likely still is.

How to return an atomic from an array of atomics? [duplicate]

It seems that std::atomic types are not copy constructible or copy assignable.
Why?
Is there a technical reason why copying atomic types is not possible?
Or is the interface limited on purpose to avoid some sort of bad code?
On platforms without atomic instructions (or without atomic instructions for all integer sizes) the types might need to contain a mutex to provide atomicity. Mutexes are not generally copyable or movable.
In order to keep a consistent interface for all specializations of std::atomic<T> across all platforms, the types are never copyable.
Technical reason: Most atomic types are not guaranteed to be lock-free. The representation of the atomic type might need to contain an embedded mutex and mutexes are not copyable.
Logical reason: What would it mean to copy an atomic type? Would the entire copy operation be expected to be atomic? Would the copy and the original represent the same atomic object?
There is no well-defined meaning for an operation spanning two separately atomic objects that would make this worthwhile. The one thing you can do is transfer the value loaded from one atomic object into another. But the load directly synchronizes only with other operations on the former object, while the store synchronizes with operations on the destination object. And each part can come with completely independent memory ordering constraints.
Spelling out such an operation as a load followed by a store makes that explicit, whereas an assignment would leave one wondering how it relates to the memory access properties of the participating objects. If you insist, you can achieve a similar effect by combining the existing conversions of std::atomic<..> (requires an explicit cast or other intermediate of the value type).
.

C++11 STL container that supports move-only types and has O(1) write-access to beginning and end

I am developing an application where I need to queue up some move-only types and I need fast write-access to the beginning and the end of the container (mainly adding elements fast).
At first glance I wanted to use std::deque<T> but it requires that T is copy-constructible, so it won't do the job.
I am now considering std::vector, but I'm worried that adding elements to the beginning of the vector would be really slow because of reallocating all the stuff.
Any suggestions on such container?
Note on operations I need (on std::deque):
emplace_back
emplace_front
pop_front
empty
front
These are the operations used currently (my implementation now uses std::shared_ptr to make move-only types copyable)
The exact type I need to queue is the move-only version of std::function<void()>. If I try the move-only version with std::deque I get the following compiler errors (clang++):
error: use of deleted function ‘std::packaged_task<_Res(_ArgTypes
...)>::packaged_task(const std::packaged_task<_Res(_ArgTypes ...)>&)
[with _Res = void; _ArgTypes = {}]’ In file included from
/home/superuser/Desktop/thread_pool/thread_pool.hpp:32:0,
from /home/superuser/Desktop/thread_pool/test.cpp:1: /usr/include/c++/6/future:1513:7: note: declared here
packaged_task(const packaged_task&) = delete;
Note that you see std::packaged_task, because it is moved into a lambda wrapped by std::function<void()>.
This is a classic example of why a [MCVE] is so useful.
std::function<void()> fun = std::move(queue.front());
The above won't compile with a non-copyable content in the queue. But the queue works fine. std::deque solves your problem.
std::function requires its contents to be copyable. Even if you never move it, it requires it be copyable. std::function uses type erasure, so "how to copy" the contents is stored when you store something in it.
Here is a move-only std::function that does not do the small buffer optimization I wrote on SO two years ago.
Today I would write it differently. I would split the type erasure from the storage, and write a separate SBO storage type, then join them together to write task<Sig>.
Amusingly, packaged_task<void(Args...)> is a type erased SBO move-only wrapper for packaged_task<R(Args...)>. But it does much more, so I would avoid using it.
Now, the rules for std containers with regards to the requirements for their content have varied, with the standard regularly getting more liberal. At one point a bunch of requirements where placed on types even if it wasn't used; the current standard states that these requirements are on a per-method basis. Many compilers enforced those more liberal requirements before the standard moved (because there was little need to be strict, the standard did not demand it), so even in compilers prior to the liberalization it wasn't a problem. I am uncertain if this liberalization occurred in std::deque by C++11 or not; this is, however, an example of "if it works in your compiler, use it, because future compilers are going to support it".

Copying classes between ranges that might overlap

In C, we have the functions memcpy and memmove to efficiently copy data around. The former yields undefined behavior if the source and destination regions overlap, but the latter is guaranteed to deal with that "as expected," presumably by noticing the direction of overlap and (if necessary) choosing a different algorithm.
The above functions are available in C++ (as std::memcpy and std::memmove), of course, but they don't really work with non-trivial classes. Instead, we get std::copy and std::copy_backward. Each of these works if the source and destination ranges don't overlap; moreover, each is guaranteed to work for one "direction" of overlap.
What can we use if we want to copy from one region to another and we don't know at compile-time if the ranges may overlap or in what direction that overlap may occur? It doesn't seem that we have an option. For general iterators it may be difficult to determine if ranges overlap, so I understand why no solution is provided in that case, but what about when we're dealing with pointers? Ideally, there'd be a function like:
template<class T>
T * copy_either_direction(const T * inputBegin, const T * inputEnd, T * outputBegin) {
if ("outputBegin ∈ [inputBegin, inputEnd)") {
outputBegin += (inputEnd - inputBegin);
std::copy_backward(inputBegin, inputEnd, outputBegin);
return outputBegin;
} else {
return std::copy(inputBegin, inputEnd, outputBegin);
}
}
(A similar function with T * replaced with std::vector<T>::iterator would also be nice. Even better would be if this were guaranteed to work if inputBegin == outputBegin, but that's a separate gripe of mine.)
Unfortunately, I don't see a sensible way to write the condition in the if statement, as comparing pointers into separate blocks of memory often yields undefined behavior. On the other hand, the implementation clearly has its own way to do this, as std::memmove inherently requires one. Thus, any implementation could provide such a function, thereby filling a need that the programmer simply can't. Since std::memmove was considered useful, why not copy_either_direction? Is there a solution I'm missing?
memmove works because it traffics in pointers to contiguous bytes, so the ranges of the two blocks to be copied are well defined. copy and move take iterators that don't necessarily point at contiguous ranges. For example, a list iterator can jump around in memory; there's no range that the code can look at, and no meaningful notion of overlap.
I recently learned that std::less is specialized for pointers in a way that provides a total order, presumably to allow one to store pointers in std::sets and related classes. Assuming that this must agree with the standard ordering whenever the latter is defined, I think the following will work:
#include <functional>
template<class T>
T * copy_either_direction(const T * inputBegin, const T * inputEnd, T * outputBegin) {
if (std::less<const T *>()(inputBegin, outputBegin)) {
outputBegin += (inputEnd - inputBegin);
std::copy_backward(inputBegin, inputEnd, outputBegin);
return outputBegin;
} else {
return std::copy(inputBegin, inputEnd, outputBegin);
}
}
What can we use if we want to copy from one region to another and we don't know at compile-time if the ranges may overlap or in what direction that overlap may occur?
This is not a logically consistent concept.
After a copy operation, you will have two objects. And each object is defined by a separate and distinct region of memory. You cannot have objects which overlap in this way (you can have subobjects, but an object type cannot be its own subobject). And therefore, it is impossible to copy an object on top of part of itself.
To move an object on top of itself is also not logically consistent. Why? Because moving is a fiction in C++; after the move, you still have two perfectly functional objects. A move operation is merely a destructive copy, one that steals resources owned by the other object. It is still there, and it is still a viable object.
And since an object cannot overlap with another object, it is again impossible.
Trivially copyable types get around this because they are just blocks of bits, with no destructors or specialized copy operations. So their lifetime is not as rigid as that of others. A non-trivially copyable type cannot do this because:
The experience with memmove suggests that there could be a solution in this case (and perhaps also for iterators into contiguous containers).
This is neither possible nor generally desirable for types which are not trivially copyable in C++.
The rules for trivial copyability are that the type has no non-trivial copy/move constructors/assignment operators, as well as no non-trivial destructor. A trivial copy/move constructor/assignment is nothing more than a memcpy, and a trivial destructor does nothing. And therefore, these rules effectively ensures that the type is nothing more than a "block of bits". And one "block of bits" is no different from another, so copying it via memmove is a legal construct.
If a type has a real destructor, then the type is maintaining some sort of invariant that requires actual effort to maintain. It may free up a pointer or release a file handle or whatever. Given that, it makes no sense to copy the bits, because now you have two objects that reference the same pointer/file handle. That's a bad thing to do, because the class will generally want to control how that gets handled.
There is no way to solve this problem without the class itself being involved in the copy operation. Different class have different behavior with respect to managing their internals. Indeed, that is the entire purpose of objects having copy constructors and assignment operators. So that a class can decide for itself how to maintain the sanity of its own state.
And it doesn't even have to be a pointer or file handle. Maybe each class instance has a unique identifier; such a value is generated at construction time, and it never gets copied (new copies get new values). For you to violate such a restriction with memmove leaves your program in an indeterminate state, because you will have code that expects such identifiers to be unique.
That's why memmoveing for non-trivially copyable types yields undefined behavior.

What is the difference between future and shared_future?

What is the difference between future and shared_future?
In what cases we must use shared_future instead of future?
I was trying to find good documentation that will contrast these two features of C++11, and I could not find an answer (easy/readable at least) on the web.
This is my current understanding of the differences
future object could be queried only once for the get().
shared_future could be queried any number of times.
use case:
If multiple threads are dependent on the result of an asynchronous task, then we must use shared_future.
If the future object needs be queried multiple times in the same thread then we must use shared_future instead.
Any more information, gotchas or general guidelines are welcome...
The motivation for these two future types goes back to move semantics, move-only types, and the new C++11 feature to return move-only types from ordinary functions.
In C++98/03, if you wanted to return a type from a factory function:
A
make_A()
{
A a;
// ...
return a;
}
then A had to be CopyConstructible. Then, brand new in C++11, we can return A even if it is not CopyConstructible, it need only be MoveConstructible.
But what happens if you try to execute make_A concurrently, say using futures. Wouldn't it be a crime if you could only parallelize make_A if A is CopyConstructible?! You would have to give up one optimization while chasing another!
So future<R> only requires R to be MoveConstructible. But you can only get it once, because you're moving from the stored result.
But getting the same result for multiple threads is a real need too. So shared_future<R> allows that, but requires R to be CopyConstructible.