When should I use std::thread::detach?

C++C++11Stdthread

C++ Problem Overview


Sometime I have to use std::thread to speed up my application. I also know join() waits until a thread completes. This is easy to understand, but what's the difference between calling detach() and not calling it?

I thought that without detach(), the thread's method will work using a thread independently.

Not detaching:

void Someclass::Somefunction() {
	//...

	std::thread t([ ] {
		printf("thread called without detach");
	});

	//some code here
}

Calling with detaching:

void Someclass::Somefunction() {
	//...

	std::thread t([ ] {
		printf("thread called with detach");
	});

	t.detach();

	//some code here
}

C++ Solutions


Solution 1 - C++

In the destructor of std::thread, std::terminate is called if:

  • the thread was not joined (with t.join())
  • and was not detached either (with t.detach())

Thus, you should always either join or detach a thread before the flows of execution reaches the destructor.


When a program terminates (ie, main returns) the remaining detached threads executing in the background are not waited upon; instead their execution is suspended and their thread-local objects destructed.

Crucially, this means that the stack of those threads is not unwound and thus some destructors are not executed. Depending on the actions those destructors were supposed to undertake, this might be as bad a situation as if the program had crashed or had been killed. Hopefully the OS will release the locks on files, etc... but you could have corrupted shared memory, half-written files, and the like.


So, should you use join or detach ?

  • Use join
  • Unless you need to have more flexibility AND are willing to provide a synchronization mechanism to wait for the thread completion on your own, in which case you may use detach

Solution 2 - C++

You should call detach if you're not going to wait for the thread to complete with join but the thread instead will just keep running until it's done and then terminate without having the spawner thread waiting for it specifically; e.g.

std::thread(func).detach(); // It's done when it's done

detach basically will release the resources needed to be able to implement join.

It is a fatal error if a thread object ends its life and neither join nor detach has been called; in this case terminate is invoked.

Solution 3 - C++

This answer is aimed at answering question in the title, rather than explaining the difference between join and detach. So when should std::thread::detach be used?

In properly maintained C++ code std::thread::detach should not be used at all. Programmer must ensure that all the created threads gracefully exit releasing all the acquired resources and performing other necessary cleanup actions. This implies that giving up ownership of threads by invoking detach is not an option and therefore join should be used in all scenarios.

However some applications rely on old and often not well designed and supported APIs that may contain indefinitely blocking functions. Moving invocations of these functions into a dedicated thread to avoid blocking other stuff is a common practice. There is no way to make such a thread to exit gracefully so use of join will just lead to primary thread blocking. That's a situation when using detach would be a less evil alternative to, say, allocating thread object with dynamic storage duration and then purposely leaking it.

#include <LegacyApi.hpp>
#include <thread>

auto LegacyApiThreadEntry(void)
{
    auto result{NastyBlockingFunction()};
    // do something...
}

int main()
{
    ::std::thread legacy_api_thread{&LegacyApiThreadEntry};
    // do something...
    legacy_api_thread.detach();
    return 0;
}

Solution 4 - C++

When you detach thread it means that you don't have to join() it before exiting main().

Thread library will actually wait for each such thread below-main, but you should not care about it.

detach() is mainly useful when you have a task that has to be done in background, but you don't care about its execution. This is usually a case for some libraries. They may silently create a background worker thread and detach it so you won't even notice it.

Solution 5 - C++

According to cppreference.com:

> Separates the thread of execution from the thread object, allowing > execution to continue independently. Any allocated resources will be > freed once the thread exits. > > After calling detach *this no longer owns any thread.

For example:

  std::thread my_thread([&](){XXXX});
  my_thread.detach();

Notice the local variable: my_thread, while the lifetime of my_thread is over, the destructor of std::thread will be called, and std::terminate() will be called within the destructor.

But if you use detach(), you should not use my_thread anymore, even if the lifetime of my_thread is over, nothing will happen to the new thread.

Solution 6 - C++

Maybe it is good idea to iterate what was mentioned in one of the answers above: When the main function is finished and main thread is closing, all spawn threads either will be terminated or suspended. So, if you are relying on detach to have a background thread continue running after the main thread is shutdown, you are in for a surprise. To see the effect try the following. If you uncomment the last sleep call, then the output file will be created and written to fine. Otherwise not:

#include <mutex>
#include <thread>
#include <iostream>
#include <fstream>
#include <array>
#include <chrono>

using Ms = std::chrono::milliseconds;

std::once_flag oflag;
std::mutex mx;
std::mutex printMx;
int globalCount{};
std::ofstream *logfile;
void do_one_time_task() {
	//printMx.lock();
	//std::cout<<"I am in thread with thread id: "<< std::this_thread::get_id() << std::endl;
	//printMx.unlock();
	std::call_once(oflag, [&]() {
	//	std::cout << "Called once by thread: " << std::this_thread::get_id() << std::endl; 
	//	std::cout<<"Initialized globalCount to 3\n";
		globalCount = 3;
		logfile = new std::ofstream("testlog.txt");
		//logfile.open("testlog.txt");
		});
	std::this_thread::sleep_for(Ms(100));
	// some more here
	for(int i=0; i<10; ++i){	
		mx.lock();
		++globalCount;
		*logfile << "thread: "<< std::this_thread::get_id() <<", globalCount = " << globalCount << std::endl;
		std::this_thread::sleep_for(Ms(50));
		mx.unlock();
		std::this_thread::sleep_for(Ms(2));
	}

	std::this_thread::sleep_for(Ms(2000));
	std::call_once(oflag, [&]() {
		//std::cout << "Called once by thread: " << std::this_thread::get_id() << std::endl;
		//std::cout << "closing logfile:\n";
		logfile->close();
		});

}

int main()
{
	std::array<std::thread, 5> thArray;
	for (int i = 0; i < 5; ++i)
		thArray[i] = std::thread(do_one_time_task);

	for (int i = 0; i < 5; ++i)
		thArray[i].detach();

	//std::this_thread::sleep_for(Ms(5000));
	std::cout << "Main: globalCount = " << globalCount << std::endl;

	return 0;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJinbom HeoView Question on Stackoverflow
Solution 1 - C++Matthieu M.View Answer on Stackoverflow
Solution 2 - C++6502View Answer on Stackoverflow
Solution 3 - C++user7860670View Answer on Stackoverflow
Solution 4 - C++GreenScapeView Answer on Stackoverflow
Solution 5 - C++DinoStrayView Answer on Stackoverflow
Solution 6 - C++rezeliView Answer on Stackoverflow