I've come across classes whose only function is to continuously do some work in a loop and they are designed such that they define a public method that can be called to invoke this member function in a new std::thread. I'm referring to something like this:
class ThreadLooper {
public:
ThreadLooper(const std::string &thread_name)
: thread_name_{thread_name}, loopCounter_{0} {}
~ThreadLooper() {
cout << thread_name_ << ": destroyed and counter is " << loopCounter_
<< std::endl;
}
void run() {
std::thread([this]() { detachedThreadLoop(); }).detach();
}
private:
void detachedThreadLoop() {
cout << thread_name_ << ": detachedThreadLoop() started running"
<< std::endl;
while (true) {
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(2s);
++loopCounter_;
cout << thread_name_ << ": counter is " << loopCounter_ << std::endl;
}
}
std::string thread_name_;
std::atomic_uint64_t loopCounter_;
};
int main() {
cout << "In main()" << std::endl;
{
ThreadLooper threadLooper{"looper1"};
threadLooper.run();
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(20s);
cout << "main() done sleeping, exiting block scope..." << std::endl;
}
while (true) {
using namespace std::literals::chrono_literals;
std::this_thread::sleep_for(20s);
cout << "main() woke up..." << std::endl;
}
return 0;
}
It seems like because the function running in the detached thread has a pointer to the instance but can continue to run beyond the lifetime of that instance this is bad. I've seen other classes where the thread isn't detached and then in the destructor a flag is set to tell the thread loop to exit and the thread is then joined in the destructor. It seems like the latter is the correct way to do this and that the former relies on the fact that the class will only be used in situations where instances of it live for the duration of the program. Is this correct or am I missing something?
Type x, *p = &x; return p;in someType *foo(). Calling that function, then exercising the result after the object it long gone, invokes UB.thishere is why I wasn't as sure as with the other examples you provided.