Reputation: 2722
Say I have a worker thread tWorker
, which is initialized when Boss
is constructed and tells it to do work()
, until bRetired
is true. An std::mutex
, mtx
, locks some data (vFiles
) so that tWorker
owns it when he's working on it.
How do I make tWorker
"commit suicide" once bRetired
becomes true
? How would the mutex
be destroyed when the thread stops execution?
I've read that std::thread
objects cannot be interrupted in any way. Does letting the thread do nothing (or calling std::this_thread::yield()
) provide the same effect as killing the thread?
class Boss {
private:
std::thread tWorker;
std::mutex mtx;
bool bRetired;
std::vector< std::string > vFiles;
void work() {
while ( bRetired == false ) {
// Do your job!
mtx.lock();
// ... Do something about vFiles ...
mtx.unlock();
}
// tWorker has retired, commit suicide
// ** How? **
// Does this suffice if I want to "kill" the thread?
std::this_thread::yield();
}
public:
Boss() {
bRetired = false;
tWorker = std::thread( &Boss::work, this );
// Have worker do its job independently
// **Bonus Question** : Should this be tWorker.join() or tWorker.detach()?
tWorker.detach();
}
retire() {
bRetired = true;
}
}
Notes
Upvotes: 11
Views: 40836
Reputation: 121961
The call to std::thread::yield()
is unrequired and does not kill the calling thread:
Provides a hint to the implementation to reschedule the execution of threads, allowing other threads to run.
Just exit the function to exit the thread.
Note that the use of bRetired
is incorrect as two threads can be accessing the same memory location and one of those threads is modifying it: this is undefined behaviour. Also, the change made in the function retire()
, a different thread, will not be seen by the thread executing run()
: use atomic<bool>
for atomicity and visibility.
If join()
was used within the constructor the constructor would not return until the thread exited, which would never happen as it would be impossible to call retire()
because the object would not be available (as the constructor would not have returned). If it is required to synchronize with the exiting of the thread then do not detach()
but join()
in the retire()
function:
void retire() {
bRetired = true;
tWorker.join();
}
Use RAII for acquiring mutex
es (std::lock_guard
for example) to ensure it always released. The mutex
will be destroyed when it goes out of scope, in this case when its containing class is destructed.
Upvotes: 5
Reputation: 136208
How do I make tWorker "commit suicide" once bRetired becomes true?
You let the control flow exit the thread function. That std::this_thread::yield()
call in unnecessary.
How would the mutex be destroyed when the thread stops execution?
That mutex is a member of Boss
class. It gets destroyed in the destructor of Boss
when the object is getting destroyed.
I've read that std::thread objects cannot be interrupted in any way.
C++ API does not provide means to terminate an arbitrary thread. There has to be a way to tell a thread to terminate and then wait till it does, as you intend to do.
Does letting the thread do nothing (or calling std::this_thread::yield()) provide the same effect as killing the thread?
No.
There is a race condition on bRetired
variable though. It either needs to be std::atomic<bool>
or it should only be read and modified only when that mutex is locked.
Upvotes: 6