【发布时间】:2012-12-05 23:59:21
【问题描述】:
我有一个作为 linux 服务运行的 C++ 程序。某些程序的命令行选项只是在其配置文件中设置值然后退出,然后需要重新启动服务以获取新配置。为了让服务不间断地继续运行,它的工作原理如下:
- 后台服务在系统启动时启动
- 后台服务创建一个“config watchdog”线程监控配置文件
- 用户从命令行运行“progname 选项”
- 配置文件已修改
- 程序退出的命令行实例
- 后台服务配置看门狗线程检测到配置更改,触发重启
当程序在读取新配置后重新启动时,我正在调用 execv 以便它将与原始实例保持在同一进程空间中,以便它可以继续作为服务进行管理。问题是 execv 没有按预期运行,而是终止现有进程并在新进程中重新启动。因为 PID 不再匹配,如果我在此之后尝试运行“service progname stop/restart”,它将无法正常工作,“stop”将使服务继续运行,“restart”将产生程序的重复实例.
我已经确认传递给 execv 的 argv[0] 是可执行文件的完整路径,因此它不应该通过 shell 在 PATH 中搜索可执行文件(这也应该被我的事实阻止) m 使用 execv 而不是 execvp),我已经阅读过有关在其他应用程序中导致类似问题的信息。
【问题讨论】:
-
确实如此。所有 exec 系列函数替换当前进程。另外,请考虑使用传统的 SIGHUP 而不是线程观察器。
-
是的,exec-family 函数替换了当前进程,但由于没有创建新进程,因此不应更改 PID。我通过使用 gdb 附加到服务实例发现的是,当调用 execv() 时,gdb 最初正确地遵循 exec 调用并打印“执行新程序 /path/to/program”,重新加载所有调试符号,但随后使用“新”实例的 PID 分离并打印“从子进程 XXX 分叉后分离”。在我的程序中的任何地方都没有对 fork() 的调用,因此 execv 调用似乎由于某种原因导致了分叉
-
到目前为止,消除原理会让我们相信你的程序确实分叉了,你应该在寻找分叉!更多的 gdb-foo 怎么样(例如“catch fork”,或者在 exec 之后设置“break fork”)。这里可能还有其他一些设计问题!看门狗线程足够公平;执行服务是邪恶的(!!);允许重复实例本身就是一个问题(使用flock或lockf创建一个锁文件)。