I'm working on a project that requires to execute some processes inside a docker container. I want to handle the case when the process doesn't terminate on time (let's say within 10 s).
I'm using this DockerClientpp library for managing the containers that basically just makes HTTP reqs to the Docker socket. Everything is fine up to this point.
To stop a container that is taking too long I'm using a separate thread. The problems is that I was able to implement it using ptheads but I cannot find a way using std::thread and lambas
Here is my working implementation with pthread
void *ContainerManager::spawnKiller(void *ref) {
ContainerManager *self = (ContainerManager *)ref;
std::unique_ptr<DockerClientpp::DockerClient> dc(new DockerClientpp::DockerClient());
std::cout << "[slave]forceStop(): Waiting " << self->timeOut << " before stopping " << self->activeId << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(self->timeOut));
try {
dc->stopContainer(self->activeId);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
pthread_exit(0);
}
void ContainerManager::execute() {
pthread_t killerId;
pthread_create(&killerId, nullptr, &(ContainerManager::spawnKiller), (void *)this);
pthread_detach(killerId);
}
And here is my std::thread and lambda implementation that fails with SEGFAULT as soon as I try to detach the thread.
void ContainerManager::execute() {
std::thread([this]() {
std::this_thread::sleep_for(std::chrono::seconds(timeOut));
try {
dc->stopContainer(activeId);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
}).detach();
}
And this is what gdb shows
Thread 1 "test" received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00000000007c6801 in std::thread::detach() ()
#2 0x0000000000410785 in ContainerManager::execute (this=0x7fffffffe2a0, processName=...)
at ../container_manager.cpp:223
#3 0x0000000000412c99 in ContainerManager::executeNew (this=0x7fffffffe2a0, processName=...,
replace=false, language=@0x7fffffffe020: ContainerManager::GO) at ../container_manager.cpp:336
#4 0x00000000004094a9 in main () at test.cpp:36
I tried with a regular function instead of a lamba, I tried capturing the parameters, I also tried passing the parameters as arguments but I'm stuck.
I haven't tried allocating the thread dynamically with new thread(...)
but from my understanding even if the std::thread
variable goes out of scope, the thread is still alive.
Do you have any suggestion on what I'm doing wrong? I feel like I'm really missing something about std::thread and lambda.
The execute method is a method of the class ContainerManager that it's guaranteed not to go out of scope before the spawned thread has terminated, also the variables that I use (timeOut
and activeId
are fields of the object)
EDIT:
It really seems there is something wrong with detach()
If I run this
void ContainerManager::execute() {
int *t = new int;
*t = timeOut;
std::string *s = new std::string;
*s = activeId;
std::thread x([&t, &s]() {
std::cout << "LOL" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(*t));
std::unique_ptr<DockerClientpp::DockerClient> _dc(new DockerClientpp::DockerClient());
try {
_dc->stopContainer(*s);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
});
std::cout << "Detaching" << std::endl;
if(x.joinable()) {
std::cout << ".. in a moment" << std::endl;
x.detach();
}
}
I get this output
Detaching
.. in a moment
Segmentation fault (core dumped)
EDIT 2 I tried running this code on my laptop and everything works fine
void ContainerManager::execute() {
// activeId and timeOut are fields of the ContainerManager object
std::thread([this]() {
std::this_thread::sleep_for(std::chrono::seconds(timeOut));
std::unique_ptr<DockerClientpp::DockerClient> dc(new DockerClientpp::DockerClient());
try {
dc->stopContainer(activeId);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
}).detach();
}