我正在用c ++运行一个简单的守护进程测试。它运行正常没有睡眠()但如果我添加sleep()func它运行一次然后保持睡眠。此外,第一次运行应该在logs / log.dat文件中打印一次“Hello”,但这也不会发生。这是代码:
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char** argv) {
FILE *f = NULL;
if ((f = fopen("logs/log.dat ", "w")) != NULL) {
if (daemon(0, 0) >= 0) {
while (true) {
fprintf(f, "%s\n", "Hello");
sleep(5);
}
} else {
fprintf(f, "%s\n", "Error detaching terminal");
}
} else {
printf("%s\n", "Cannot open log file");
}
return 0;
}
答案 0 :(得分:5)
尝试在fprintf()之后添加fflush()。它可能正在工作,但尚未将数据写入磁盘。
答案 1 :(得分:3)
daemon()
功能中有什么?特别是它是否关闭标准输入,标准输出和标准错误以外的打开文件?如果是这样,则后续fprintf()
语句将失败,因为之后调用daemon()
之前打开的文件将被关闭。
如果你的代码测试了打印函数的返回值,你就可以找到它(虽然你可能不得不打开一个带有绝对路径名的日志文件,以便能够从守护进程中报告它)
检查此假设的最快方法可能是在守护进程后打开日志文件。
请注意,某些daemon()
例程也会更改目录 - 通常更改为根目录。这会让您对日志文件的相对路径感到头疼。
在MacOS X上,daemon(3)
函数在<stdlib.h>
中提供了声明;它是在BSD 4.4中引入的,似乎是:
概要
#include <stdlib.h> int daemon(int nochdir, int noclose);
描述
守护进程()函数用于希望从控制终端分离的程序 作为系统守护进程在后台运行。 [...]
除非参数nochdir非零,否则daemon()会将当前工作目录更改为根目录(/)。
除非参数noclose为非零,否则daemon()会将标准输入,标准输出和标准错误重定向到/ dev / null。
您可以检查FreeBSD 8源代码。
由于对daemon()
的调用两次传递0,因此代码执行chdir("/")
并将文件描述符0,1,2重新连接到'/ dev / null'。手册页继续讨论fork(2)
和setsid(2)
。因此,我们可以确信您的程序将其标准I / O通道重新连接到/ dev / null,并将当前目录更改为根目录。
手册页确实提到您应该小心确保所有打开的文件都具有大于2的文件描述符以避免问题。你可以在某处打印'fileno(f)' - 它是一个整数 - 并确保它大于2.如果它不够大,那么这就是你的麻烦的原因;不要使用任何stdin,stdout或stderr已经关闭的程序来调用你的程序。
这还没有解释文件中缺少数据,也没有解释为什么sleep()
会影响结果。当然,sleep()
的经典实现提示信号和SIGALRM; daemon(3)
的手册页提到了SIGHUP。但是,sleep(3)
的FreeBSD 8实现使用nanosleep(2)
系统调用。
所以,我将同意Jay的建议 - 文件将被完全缓冲,你必须等待大量的5秒周期来打印足够的数据来刷新缓冲区(可能需要4096字节,每5秒6个字节,将需要大约一个小时来生成文件中的任何内容)。添加fflush()
最有可能解决“消息不出现”问题。或者,使用setvbuf(f, 0, _IONBF, 0);
关闭所有缓冲,或使用setvbuf(f, 0, _IOLBF, BUFSIZ);
启用线缓冲。 sleep()
是一个因素,因为它会大大减慢处理速度。
答案 2 :(得分:0)
我有类似的问题,但因为我使用了syslog,所以使用fflush()是不可能的。 在我的情况下,解决方案是更改调试消息。
自:
syslog(LOG_DEBUG, "DEBUG: tick");
要:
syslog(LOG_DEBUG, "DEBUG: tick %d", i); // i is increased in the loop
所以每次都有不同的消息。