【发布时间】:2019-11-28 01:28:48
【问题描述】:
我正在做一个需要在 docker 容器内执行一些进程的项目。我想处理进程没有按时终止(比如说 10 秒内)的情况。
我正在使用这个DockerClientpp 库来管理容器,这些容器基本上只是向 Docker 套接字发出 HTTP 请求。到目前为止一切都很好。
为了停止一个耗时过长的容器,我使用了一个单独的线程。问题是我能够使用 ptheads 来实现它,但我找不到使用 std::thread 和 lambas
的方法这是我使用 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);
}
这是我的 std::thread 和 lambda 实现,一旦我尝试分离线程,SEGFAULT 就会失败。
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();
}
这就是 gdb 显示的内容
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
我尝试使用常规函数而不是lamba,我尝试捕获参数,我还尝试将参数作为参数传递,但我被卡住了。
我没有尝试使用new thread(...) 动态分配线程,但据我了解,即使std::thread 变量超出范围,线程仍然存在。
你对我做错了什么有什么建议吗?我觉得我真的错过了关于 std::thread 和 lambda 的一些东西。
execute 方法是 ContainerManager 类的一个方法,它保证在生成的线程终止之前不会超出范围,也是我使用的变量(timeOut 和 activeId 是对象的字段)
编辑:
看来detach()确实有问题
如果我运行这个
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();
}
}
我得到这个输出
Detaching
.. in a moment
Segmentation fault (core dumped)
编辑 2 我尝试在笔记本电脑上运行此代码,一切正常
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();
}
【问题讨论】:
-
我没有看到
dc在 lambda 版本中被分配,而在 pthreads 版本中,它是由线程专门分配的。 -
多线程程序经常在一台机器上显示错误,而在另一台机器上却没有。有时只需要执行速度和线程同步的微小差异。
-
您说您在使用@MikevanDyke 的代码时遇到了同样的问题——您能否更新您的问题以显示您正在运行的实际代码?迈克修复了一个真正的错误,但如果有其他问题,看看你到底有什么会很有帮助。
-
你是如何在容器中启动进程的?如果你正在做
docker run -d ubuntu:14.04 /my/process,用docker run -d ubuntu:14.04 timeout 10s /my/process替换它不会有用吗?它甚至返回错误代码 124 来告诉您进程超时。 -
根据您的设计,您需要考虑使用 docker 引擎处理所有内容是否值得添加一个线程、以下解决方案中约 20 行非平凡的 c++ 代码,以及您处理的任何错误从
stopContainer()和DockerClientpp::DockerClient构造函数中丢失。
标签: c++ multithreading lambda pthreads stdthread