Can std::thread::join() be called from a non parent thread? - c++

A::thread was created by main thread. Can I join A::thread into the thread goo ?
struct A {
std::thread thread;
void foo() {
thread=std::thread{[]() { sleep(10); }};
}
};
void goo(A& a) {
a.thread.join();
}
int main() {
A a;
a.foo();
std::thread other_thread{goo, a};
other_thread.join();
};

Yes, you may. The behavior of std::thread::join is (emphasis mine):
Blocks the current thread until the thread identified by *this
finishes its execution.
It says quite explicitly "current thread", not "parent thread". Any thread can join with any other thread, so long as it has a valid handle to that other thread.
Though you have to mindful of data races when using references to thread objects. Two different threads attempting to join the same third one would be... bad.

Related

Create a std::thread object in thread A, join in thread B

Is it allowed to call join() on a std::thread object that was created in a different thread, given that the object is properly synchronized between threads?
For example:
void cleanup(std::thread t)
{
t.join();
}
int main()
{
std::thread t{[] { /* something */ }};
std::thread c{cleanup, std::move(t)};
c.join();
}
Yes. join() can be called on a valid thread object by any thread except by the thread itself.
Error Conditions
resource_deadlock_would_occur if this->get_id() == std::this_thread::get_id().
no_such_process if the thread is not valid
invalid_argument if joinable() is false

Default destructor blocked on a mutex

I got code like below for an experiment:
class Foo {
public:
Foo() : mThread(&Foo::test, this) {
}
private:
std::thread mThread;
std::mutex mMutex;
std::condition_variable mCv;
void test() {
std::unique_lock<std::mutex> lock(mMutex);
mCv.wait(lock);
}
};
int main() {
Foo foo;
usleep(1000);
std::cout << "wake up" << std::endl;
}
And the code will block at the destructor of Foo, after debugging, I found out that the thread is blocked on futex_wait, but double check the document of wait() of condition_variable, it says that
At the moment of blocking the thread, the function automatically calls
lck.unlock(), allowing other locked threads to continue.
So why my code still blocked at mMutex since mCv has unlocked?
P.S. I know this design pattern has problems, I just curious if I'm missing some knowledge about thread conditions.
Your program exhibits undefined behavior. At the closing brace of main, foo is destroyed, and so are its member variables, beginning with mCv. The standard says:
[thread.condition.condvar]/5
~condition_variable();
Requires: There shall be no thread blocked on *this. [ Note: That is, all threads shall have been notified... —end note ]
Your program violates the Requires clause, as test in another thread waits on mCv and has not been notified.

std::thread thread spun off in object, when does it terminate?

If I spin off an std::thread in the constructor of Bar when does it stop running? Is it guaranteed to stop when the Bar instance gets destructed?
class Bar {
public:
Bar() : thread(&Bar:foo, this) {
}
...
void foo() {
while (true) {//do stuff//}
}
private:
std::thread thread;
};
EDIT: How do I correctly terminate the std::thread in the destructor?
If I spin off an std::thread in the constructor of Bar when does it
stop running?
the thread will run as long as it executing the callable you provided it, or the program terminates.
Is it guaranteed to stop when the Bar instance gets destructed?
No. In order to guarantee that, call std::thread::join in Bar destructor.
Actually, if you hadn't call thread::join or thread::detach prior to Bar::~Bar, than your application will be terminated by calling automatically to std::terminate. so you must call either join (preferable) or detach (less recommended).
you also want to call therad::join on the object destructor because the spawned thread relies on the object to be alive, if the object is destructed while your thread is working on that object - you are using destructed object and you will have undefined behavior in your code.
Short answer: Yes and no. Yes, the thread ends, but not by the usual way (killing the thread), but by the main thread exiting due to a std::terminate call.
Long answer: The thread can only be safely destructed when the underlying function (thread) has finished executing. This can be done in 2 ways
calling join(), which waits for the thread to finish (in your case, never)
calling detach(), which detaches the thread from the main thread (in this case, the thread will end when the main thread closes - when the program terminates).
If the destructor is called if all of those conditions don't apply, then std::terminate is called:
it was default-constructed
it was moved from
join() has been called
detach() has been called
The C++ threading facilities do not include a built-in mechanism for terminating a thread. Instead, you must decide for yourself: a) a mechanism to signal the thread that it should terminate, b) that you do not care about the thread being aborted mid-operation when the process terminates and the OS simply ceases to run it's threads any more.
The std::thread object is not the thread itself but an opaque object containing a descriptor/handle for the thread, so in theory it could be destroyed without affecting the thread, and there were arguments for and against automatic termination of the thread itself. Instead, as a compromise, it was made so that destroying a std::thread object while the thread remained running and attached would cause the application to terminate.
As a result, In it's destructor there is some code like this:
~thread() {
if (this->joinable())
std::terminate(...);
}
Here's an example of using a simple atomic variable and checking for it in the thread. For more complex cases you may need to consider a condition_variable or other more sophisticated signaling mechanism.
#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>
class S {
std::atomic<bool> running_;
std::thread thread_;
public:
S() : running_(true), thread_([this] () { work(); }) {}
void cancel() { running_ = false; }
~S() {
if ( running_ )
cancel();
if ( thread_.joinable() )
thread_.join();
}
private:
void work() {
while ( running_ ) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "tick ...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "... tock\n";
}
std::cout << "!running\n";
}
};
int main()
{
std::cout << "main()\n";
{
S s;
std::this_thread::sleep_for(std::chrono::milliseconds(2750));
std::cout << "end of main, should see a tock and then end\n";
}
std::cout << "finished\n";
}
Live demo: http://coliru.stacked-crooked.com/a/3b179f0f9f8bc2e1

std::thread::join blocks indefinitely out of main

std::thread::join does not return, even if the thread routine is exited.
Guess, I have a class.
class A
{
public:
A()
{
this->thr = std::thread(&A::foo, this);
}
~A()
{
this->join();
}
void join()
{
this->cond.notify_all();
if (this->thr.joinable())
{
this->thr.join();
}
}
private:
void foo()
{
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
this->cond.wait(lck);
MessageBox(L"I'm done!");
}
private:
std::thread thr;
std::condition_variable cond;
};
My application contains the only instance of A. It is a global variable.
If A::join is called from the destructor, std::thread::join blocks forever.
If I call A::join manually (e.g. before exiting main), everything is alright.
My main looks like this:
A a;
int main()
{
auto timeout = std::chrono::seconds(3);
std::this_thread::sleep_for(timeout);
// a.join();
}
By the way, MessageBox is always executed.
Is that the same problem as here?
Yes it is the same bug as in the referenced link since your example also hangs on _Thrd_join. You could be interrested in this question which contains a far more detailed analysis.
from your comment
"It doesn't seem to be a great solution. I works, but what if the main
is not so trivial? There're a lot of different ways of exiting from my
application. Thus, I've got to join my threads manually every time I
need it?"
how about making A a std::unique_ptr within your main. that way, no matter how your main exits, it'll always destroy A before exiting main() and you won't have this problem.

Can the thead joinable-join have a race condition? how do you get around it?

Lets say I have the following class
class A
{
public:
A()
{
my_thread=std::thread(std::bind(&A::foo, this));
}
~A()
{
if (my_thread.joinable())
{
my_thread.join();
}
}
private:
std::thread my_thread;
int foo();
};
Basically, if my thread completes between the joinable and join calls, then my_thread.join will wait forever? How do you get around this?
Basically, if my thread completes between the joinable and join calls, then my_thread.join will wait forever?
No. A thread is still joinable after it has completed; it only becomes unjoinable once it has been joined or detached.
All threads must be joined or detached before the controlling thread object is destroyed.