Threads Lifetime

Contents[Show]

The parent has to take care of their child. This simple idea has big consequences for a thread lifetime. The following program starts a thread that displays its ID.

// threadWithoutJoin.cpp

#include <iostream>
#include <thread> int main(){ std::thread t([]{std::cout << std::this_thread::get_id() << std::endl;}); }

 

But the program run results in an unexpected result.

 threadForgetJoin 

What's the reason?

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

join and detach

The lifetime of the created thread t ends with its callable unit. The creator has two choices. First: it waits until its child is done (t.join()). Second: it detaches itself from its child: t.detach(). A thread t with the callable unit (you can create threads without a callable unit) is joinable, in case there were no t.join() or t.detach calls to the thread. A joinable thread destructor throws  std::terminate  exception. Thus, the program terminates. That is the reason, the actual run terminated unexpectedly.

The solution to this problem is simple. By calling t.join(), the program behaves as it should.

// threadWithJoin.cpp

#include <iostream>
#include <thread> int main(){ std::thread t([]{std::cout << std::this_thread::get_id() << std::endl;}); t.join(); }

 

threadJoin

A short side note: The challenges of detaching

Of course, you can use t.detach() instead of t.join() in the program above. The thread t is not joinable anymore, and its destructor didn't call std::terminate. Seems terrible because now the program behavior is undefined because the lifetime of the object std::cout is not ensured. The execution of the program goes a little bit odd.

 

threadDetach

I will elaborate more on this issue in the following article.

Moving threads 

Until now, it was quite easy. But that has not to be forever.

It is impossible to copy a thread (copy semantic); you can only move (move semantic) it. If a thread is moved, it's a lot more challenging to deal with its lifetime in the right way.

// threadMoved.cpp

#include <iostream>
#include <thread> #include <utility> int main(){ std::thread t([]{std::cout << std::this_thread::get_id();}); std::thread t2([]{std::cout << std::this_thread::get_id();}); t= std::move(t2); t.join(); t2.join(); }

 

Both threads - t1 and t2 should do a simple job: print their IDs. In addition, thread t2 will be moved to t: t= std::move(t2). In the end, the main thread takes care of its children and joins them. But wait. That's far away from my expectations:

 threadMove

What is going wrong? We have two issues:

  1. By moving (taking ownership of)  the thread t2, t gets a new callable unit, and its destructor will be called. So it's destructor calls std::terminate, because it is still joinable.
  2. Thread t2 has no associated callable unit. The invocation of join on a thread without a callable unit leads to the exception std::system_error.

I fixed both errors.

// threadMovedFixed.cpp

#include <iostream>
#include <thread> #include <utility> int main(){ std::thread t([]{std::cout << std::this_thread::get_id() << std::endl;}); std::thread t2([]{std::cout << std::this_thread::get_id() << std::endl;}); t.join(); t= std::move(t2); t.join(); std::cout << "\n"; std::cout << std::boolalpha << "t2.joinable(): " << t2.joinable() << std::endl; }

 

As a result, thread t2 is not joinable anymore.

threadMoveRight

scoped_thread

If it's too bothersome for you to take care of the lifetime of your threads by hand, you can encapsulate a std::thread in your wrapper class. This class should automatically call join in his destructor. Of course, you can go the other way around and call detach. But you know, there are a few issues with detachment.

Anthony Williams created such a valuable class. He called it scoped_thread. The constructor checks that the thread is joinable and joins it finally in the destructor. Because the copy constructor and copy assignment operator is declared delete, objects of scoped_thread can not be copied to or assigned from.

// scoped_thread.cpp

#include <iostream>
#include <thread> #include <utility> class scoped_thread{ std::thread t; public: explicit scoped_thread(std::thread t_): t(std::move(t_)){ if ( !t.joinable()) throw std::logic_error("No thread"); } ~scoped_thread(){ t.join(); } scoped_thread(scoped_thread&)= delete; scoped_thread& operator=(scoped_thread const &)= delete; }; int main(){ scoped_thread t(std::thread([]{std::cout << std::this_thread::get_id() << std::endl;})); }

What's next?

In the next post, I will deal with passing data to threads. (Proofreader Alexey Elymanov)

 

 

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up code TakeUpCode 450 60

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

 

 

Comments   

0 #21 APK Download 2016-11-28 12:39
What's up, this weekend is fastidious designed for me, because this point in time i am reading this fantastic educational paragraph here at my house.
Quote
0 #22 Huug Schenk 2017-03-22 16:41
Is the call to t2.joinable() after doing an std::move(t2) safe? I thought the only thing that is guaranteed about t2 after the move is that it can be assigned to.
Quote
+1 #23 Dario Entertainer 2017-04-13 22:27
Just desire to say your article is as amazing. The clearness in your submit is simply spectacular
and i could assume you are knowledgeable in this subject.

Fine with your permission allow me to snatch your RSS feed to stay up to date with impending post.

Thanks a million and please carry on the enjoyable work.
Quote
0 #24 Marianne 2017-09-02 04:48
Hey very interesting blog!
Quote

Stay Informed about my Mentoring

 

Mentoring

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 2310

Yesterday 4371

Week 38117

Month 168242

All 12056008

Currently are 187 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments