Moving an argument into a std::thread? - c++

Please consider the following code:
void h(M m2)
{
...
}
int main()
{
while (true) {
M m1 = ...;
std::thread t(h, std::move(m1));
t.detach();
}
}
Is it guaranteed that m2 is properly move-d constructed from m1 before m1 is destroyed? Or is there a race?

The standard seems clear to me:
Effects: Constructs an object of type thread. The new thread of execution executes INVOKE (DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) with the calls to
DECAY_COPY being evaluated in the constructing thread.
Since the copy is made in the calling thread it must complete before the constructor invocation returns.
Construction of m2 is done from a different object (the result of the DECAY_COPY), not from m1, so it doesn't matter whether m1 has been destroyed or not.
The result of the DECAY_COPY must be stored somewhere by the implementation so that it doesn't go out of scope until the target function has been initialized, but that is the implementation's job to get right. Destruction of m1 doesn't have any effect on it.

Related

Lifetime Extension of Temporary Object in Multithreaded Context

I have the following scenario:
void thread_func(const Widget& w) { /*does something here...*/ }
int main() {
Widget w{ /* some arguments */ };
std::thread t(thread_func, std::move(w));
t.detach();
// lots of other stuff down here ...
}
Now I know that temporary objects, when bound to const T& parameters in a function call have their lifetime extended until the completion of the expression in which the call occurs. But in this multithreaded context, does the "completion of the expression in which the call occurs" refer to the construction of t, or to the completion of thread_func, since thread_func is (at the very least, conceptually) called at the end of t's constructor?
In a scenario with a single thread the answer is clear:
Widget h() { return Widget{/* some arguments */}; }
void g(const Widget& x) { /* do something */ }
void f() {
g(h());
}
the lifetime of the temporary within the call to g lives until g has finished executing, since execution pauses within f, begins in g, and only resumes in f once g has finished executing. In a multithreaded environment, the answer is more confusing to me because construction happens in a single thread, but the execution directly following construction happens concurrently.
This is not a lifetime extension situation. All temporaries live until then end of the full-expression, i.e. the outermost ;.
std::thread t(thread_func, std::move(w)); - this is a full-expression. So yes, the thread is starting when the expression is already ended.
Your thread is started with a reference to the original object, which must be keep alive for as long as it's needed in the thread.
Bonus notes:
You can't move into an lvalue-reference. Your std::move has no effect. But even if you changed the function to accept an rvalue reference, it would not change the fact that the original object needs to be kept alive externally. Remember that std::move does not move anything. What would change it though is if you simply accepted it by value.
void thread_func(Widget w) { /*does something here...*/ }
Detaching a thread is almost never needed. In your example the program will end when the main thread finishes, it will not wait for any other thread to finish. Consider joining your thread before main() returns instead.

Visibility of a variable across threads in c++

Given the following code, Is it guaranteed to see the latest value 4 of a ?
int a;
mutex mtx;
void f() {
unique_lock<mutex> lck(mtx);
// read(a);
// is it guarantee it will see the value 4?
}
int main() {
a = 4;
thread(f);
}
Yes, it is guaranteed:
32.4.2.2 Constructors [thread.thread.constr]
Synchronization: The completion of the invocation of the constructor
synchronizes with the beginning of the invocation of the copy of f.
In other words, the construction of std::thread itself, which occurs in the original execution thread, synchronizes with the beginning of the invocation of the thread function. Or, in other words: everything that happens before std::thread gets constructed, in the original thread, is visible in the thread function.

Can I return std::thread

Is it safe to return std::thread from a function?
eg
std::thread getWindowThread(std::function<void()> f){
std::thread t(f);
return t;
}
std::function<void()> func = [](){};
std::thread winT = getWindowThread(func);
winT.join();
Yes, it's safe, as long as the function's return value is used to initialize or assign to another std::thread object.
The only precondition for std::thread's destructor is that joinable() is false:
[thread.thread.destr]
~thread();
Effects: If joinable(), calls terminate(). Otherwise, has no effects.
To be joinable(), the thread must have an ID not equal to a value-initialized ID:
[thread.thread.member]
bool joinable() const noexcept;
Returns: get_­id() != id().
And std::thread's move constructor and move-assignment operator specify that a moved-from thread will have an ID equal to a value-initalized ID, and therefore will not be joinable():
[thread.thread.constr]
thread(thread&& x) noexcept;
Postconditions: x.get_­id() == id() and get_­id() returns the value of x.get_­id() prior to the start of construction.
[thread.thread.assign]
thread& operator=(thread&& x) noexcept;
...
Postconditions: x.get_­id() == id() and get_­id() returns the value of x.get_­id() prior to the assignment.
...
Since getWindowThread returns a function-local variable, its return value will be move-constructed from the returned object, and since winT will be move-constructed from the value returned by getWindowThread, your example is safe. The returned thread object is no longer joinable and can be destroyed.
However, if the returned value is not used to initialize or assign to another std::thread object, its destructor will call std::terminate() and crash your program. For this reason, I would recommend adding the [[nodiscard]] attribute to your function to ensure your compiler at least issues a warning in this dangerous situation (if you have access to C++17 features, otherwise there are compiler-specific extensions to enable the same behavior):
[[nodiscard]] std::thread getWindowThread(std::function<void()> f) {
std::thread t(f);
return t;
}
Yes, it's safe. That thread will be moved to winT.
Have a look std::thread's constructors. You can check that std::thread copy constructor (and copy assignment) has been deleted. See this to learn more about move constructor in C++.
When you return std::thread from the function, it's returned object is move-constructed and your variable winT will also be move-constructed as the function returns an object having value category prvalue.
std::thread winT = getWindowThread(func);
This should work and won't cause any undefined behavior. You might be thinking that once you return std::thread from the function, it will be destroyed and it's resources must be released and may be it's thread might be destroyed.
But as stated earlier, the object created in function will be move-constructed to construct winT object.
Detailed Information:
This link says that:
If *this has an associated thread (joinable() == true), std::terminate() is called.
So, to safely destroyed any std::thread object, you need to make sure it is not joinable. joinable() gives more insight on this:
So a default constructed thread is not joinable. A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable.
So, when move constructor of winT constructs it, it swaps itself with object returned from your function. After that, temporary of your function will be destroyed and since, it won't be joinable, it is safe to destroy it.

Is it ok to replace std::thread objects?

From what I could gather in C++ online documentation, assigning to a joined std::thread object should call its destructor and represents a legitimate operation. Is this the case?
Here some example to show what I mean:
#include <thread>
#include <vector>
using namespace std;
int main()
{
vector<thread> tvec;
for(int = 0; i < 3; ++i)
{
tvec.push_back(thread(foo));
}
for(size_t i = 0; i < 3; ++i)
{
tvec[i].join();
tvec[i] = thread(foo); // is this ok?
}
for(auto& t : tvec)
{
t.join();
}
}
assigning to a joined std::thread object should call its destructor
No it shouldn't! Destructors are only called when objects are destroyed, hence the name.
and represents a legitimate operation
It's fine as long as the thread is not joinable (as is the case in your example). Otherwise, terminate will be called.
If you were to read the standard, rather than dubious online "documentation", you'd find in [thread.thread.assign]
Effects: If joinable(), calls terminate(). Otherwise, assigns the state of x to *this and sets x to a default constructed state.
Calling the assignment operator on a thread checks to see if the thread is joinable() if it is then std::terminate() is called. If it is not then it assigns the state of the thread on the right hand side to the thread being assigned to. It then leaves the thread on the right hand side in a default constructed state.
This is called a move assignment. The actual assignment operator is deleted.

Is this code correctly synchronized?

I wonder if this code is fine or not:
#include <iostream>
#include <future>
struct Foo
{
Foo()
:m_a(0)
{
}
int m_a;
};
int main()
{
Foo f;
auto handle =
std::async( std::launch::async,
[](Foo* f) { std::cout << f->m_a << '\n'; } ,
&f
);
handle.get();
}
I believe m_a should be protected by a synchronization mechanism but my colleague says it is not necessary.
EDIT: To clarify my question: I am worried that the STORE operation from the constructor of Foo() happens after the LOAD operation from the other thread. I can't see what mechanism prevents the compiler from executing those instruction in this order.
EDIT: I believe an enthusiastic compiler could decide to inline the constructor, and delay the STORE operation for after the CALL operation to std::async. In which case the second thread could access m_a before it has been committed to memory.
Yes, this is correctly synchronised.
From the specification for async, C++11 30.6.8/5:
the invocation of async synchronizes with the invocation of f.
where f is the function argument to async (the lambda in your example).
Initialisation of f.m_a is sequenced before the call to async, and therefore before any access by the asynchronous function.
Furthermore,
the completion of the function f is sequenced before the shared state is made ready.
so the access must happen before the call to get() returns, and therefore before the object is destroyed.