Joinable thread in C++ - c++

http://www.cplusplus.com/reference/thread/thread/joinable/
A thread object is joinable if it represents a thread of execution.
A thread object is not joinable in any of these cases:
if it was **default-constructed**.
if it has been **moved from** (either constructing another thread object, or assigning to it).
if either of its members join or detach has been called.
What is the meaning of default constructed, here?
W.R.T moved from - When we have to put threads in a vector, we may create thread objects outside and then move them in the vector. Is this one of the cases which this moved from is referring to?
After detach has been called once, can we never join it again?

What is the meaning of default constructed, here?
It means a std::thread which was constructed with no arguments, and therefore does not represent a thread (i.e. it is not "running"). See docs: https://en.cppreference.com/w/cpp/thread/thread/thread
W.R.T moved from - When we have to put threads in a vector, we may create thread objects outside and then move them in the vector. Is this one of the cases which this moved from is referring to?
Yes, you cannot join a thread after moving it into the vector. But you can of course join the new thread object inside the vector (where it was "moved to").
After detach has been called once, can we never join it again?
That's right, you cannot join a thread which has already been joined or detached.

Related

C++ Multithreading: Do I need mutex for constructor and destructor?

For a object that will be accessed by multiple threads, do I need to have a mutex for its constructor and destructor?
My guess is I need a mutex in the destructor, since it is possible to have one thread accessing the object while another thread deleting the object.
On the other hand, I cannot think of a reason why we need a mutex in the constructor, since there cannot be other threads accessing the object before it is fully constructed.
You are unable to share object before it is constructed. If it is not shared, then only one thread uses that. Conclusion there is no need to synchronize anything in constructor (unless you are spawning a new thread).
Now destructor is called only when all strong references are ending their lifetimes. This means that when destructor is executed last strong reference is just clean up. Again this means only one thread is using object so there is no point of synchronizing.
If for some magic reason you will have race condition in constructor or destructor the bug must be in an owner of the object.
The only synchronization I can imagine has sense in destructor is joining threads futures (spawned by this object) or fulfilling promises.

Must an object's ctor and dtor be on the same thread?

With C++ RAII, the dtor gets called when the object goes out of scope. The mechanisms for multithreading always involve passing a callback to be run on a new thread. Thus, I don't think it's possible for an object to be constructed in one thread and destructed in another, since those would have to be different scopes.
Am I right about this? Or are there some cases where an objects ctor and dtor can be called in different threads?
Thus, I don't think it's possible for an object to be constructed in one thread and destructed in another, since those would have to be different scopes.
Am I right about this?
No. These functions can be called completely independent of any threading.
Or are there some cases where an objects ctor and dtor can be called in different threads?
Sure there are cases (just daily bread and butter). Think about a simple producer / consumer model and message instances exchanged between threads through a queue.
The producer thread creates the message instance and pushes it into the queue. The consumer takes it off from the queue and the messages destructor will be called after it was processed.
The mechanisms for multithreading always involve passing a callback to be run on a new thread.
False. There's plenty of cases where you just need another thread to do stuff or manage something in the background but don't care about the status. Additionally, there are other signalling methods besides callbacks (just one example would be conditional variables).
Side note: a callback could be called on any thread, including the thread that you passed the callback to. It all depends on how you design the system. You don't have to make a new thread every time you invoke a callback (although that's one way to do it).
Thus, I don't think it's possible for an object to be constructed in one thread and destructed in another, since those would have to be different scopes.
False. Shared pointers allow pointers to objects to be passed around threads and once all references to the object are removed, then the object is destructed.
An example would be a networking thread that constructs an object to represent some message received from the network. That thread then puts that object on a shared queue and some other processing thread processes that message. Once the processing thread has completed, it can destruct the object and free the resources for other things.

Destructor in a multithreaded environment?

I was wondering what would happen in such a class:
class MyClass
{
private:
std::vector<int> iVector;
void Worker()
{
//Lots of stuff done with iVector
//adding, removing elements, etc.
}
}
Let's say I create a thread (invoked by one of the class member functions) that uses iVector and modifies it. Besides this worker, none of the other member functions of the class reads or modifies this std::vector.
Everything seems fine as worker thread is the only one using iVector.
But what would happen when one instance of the object is destroyed? Even if the object is destroyed after the worker thread is finished, destructor for iVector would be invoked from the main thread. Would this lead to undefined behavior?
Thanks!
Firstly I would suggest running a std::join (or your library equivalent) on the thread in the destructor. This will ensure the thread is properly finished and synchronized before the vector destructor runs. This is important as the vector's lifetime must exceed the thread using it.
The C++11 standard and presumably later ones state in 30.3.1.5:
5: Synchronization: The completion of the thread represented by *this
synchronizes with (1.10) the corresponding successful join() return. [
Note: Operations on *this are not synchronized. — end note ]
Now we have to examine 1.10 for more detail, first this section states:
3: The value of an object visible to a thread T at a particular point
is the initial value of the object, a value assigned to the object by
T, or a value assigned to the object by another thread, according to
the rules below.
Honestly, this is difficult to parse, it does not specify exactly what kind of synchronization join offers and seems to imply it synchronizes only the thread itself and not data it has accessed. Therefore I would go the safe route and run atomic_thread_fence(memory_order_acquire) after join in the main thread, and atomic_thread_fence(memory_order_release) in the child thread just before it finishes which should guarantee full happens before semantics and no UB.
If an execution thread is using the ivector class member, and another thread destroys the object with this class member, the continued use of the ivector class member results in undefined behavior.
Even if the object is destroyed after the worker thread is finished,
destructor for iVector would be invoked from the main thread. Would
this lead to undefined behavior?
No. As you've described, this situation is not undefined behavior. The C++ standard does not require an object to be destroyed by the same execution thread that created the object. It's fine for one execution thread to grow, resize the vector, then go away or stop using the vector, and then a different execution thread destroy the entire object.

What happens if one deletes an object with a running pthread?

I have an object that uses pthreads. Its constructor creates several threads.
The class's destructor calls pthread_join on all these threads.
What would happen during a delete, if it didn't? I.e., what happens to a non-terminated thread, if the delete operator suddenly tries to deallocate the object?
Thanks in advance for all replies. :)
With the join, your destructor will block until all of the joined threads have exited.
pthread_join
The pthread_join() function waits for the thread specified by thread
to terminate. If that thread has already terminated, then
pthread_join() returns immediately. The thread specified by thread
must be joinable.
If you don't join with the threads, they will continue to run. This can have various consequences depending on if you invoke undefined behavior (eg, try to reference the deleted object after the destructor exits from one of the still running threads).
Deleting the pthread_t objects could have consequences depending on your system (I don't know every implementation of pthreads), but in general they're only references to the underlying system object representing the thread. So you will lose your reference to that thread, and potentially be unable to join with it later, but the thread would continue to run.

C++11 Multithreading : State of thread after execution

What is the state of thread after it completes its execution.?
Is it destroyed immediately after its execution or is it destroyed with parent thread.?
The std::thread object is different than a underlying thread of control (although they should map 1-on-1).
This separation is really important and it implies that std::thread and thread of control can have different life duration. For example, if you create your std::thread on the stack, you really need to call thread::detach before your object go destroyed (if you don't destructor will call terminate ). Also, as Grizzly pointed out, you can call .join() before your object destruction which will block until the execution of the thread has finished.
This also answers your question - std::thread object is not destroyed after the thread is finished - it is behaving as every other C++ object - it will be destroyed when it goes out of the scope (or gets deleted).