signal() + Alarm() 的 c 替代方案
题
我正在构建一些 FastCGI 应用程序,但 lighttpd 不会在它们闲置后将它们杀死,这让我有点烦恼,所以我试图让它们自行关闭。
我尝试使用
signal(SIGALRM, close);
alarm(300);
并让 close 函数执行 exit(0),效果几乎很好。
问题是每次主程序循环运行时都会调用 close 函数(我在每个循环中调用 Alarm(300) 来重置它)。我已经阅读了alarm()的手册页,似乎用相同的值多次调用它应该不会触发SIGALRM,所以我假设Lighttpd正在发送警报信号。
大问题!有没有办法在特定时间间隔后运行方法,并且可以在没有 SIGALRM 的情况下重置该时间间隔?如果我也能有多个闹钟就好了。
这是迄今为止的整个应用程序:
#include <stdlib.h>
#include <stdarg.h>
#include <signal.h>
#include "fcgiapp.h"
FCGX_Stream *in, *out, *err;
FCGX_ParamArray envp;
int calls = 0;
void print(char*, ...);
void close();
int main(void)
{
// If I'm not used for five minutes, leave
signal(SIGALRM, close);
int reqCount = 0;
while (FCGX_Accept(&in, &out, &err, &envp) >= 0)
{
print("Content-type: text/plain\r\n\r\n");
int i = 0;
char **elements = envp;
print("Environment:\n");
while (elements[i])
print("\t%s\n", elements[i++]);
print("\n\nDone. Have served %d requests", ++reqCount);
print("\nFor some reason, close was called %d times", calls);
alarm(300);
}
return 0;
}
void print(char *strFormat, ...)
{
va_list args;
va_start(args, strFormat);
FCGX_VFPrintF(out, strFormat, args);
va_end(args);
}
void close()
{
calls++;
// exit(0);
}
解决方案
最好的办法是:增加一个线程,这样就可以去除信号和报警,并同步线程和主代码(主线程)
其他提示
我可能会使用POSIX计时器。计时器没有使用的信号。你没有通知所有,发出信号,或者运行一个函数作为一个新的线程(我会做,因为它不会FastCGI的干扰)之间进行选择。
请确保您有<signal.h>
和<time.h>
,并链接与-lrt
首先,我要填写您的sigevent结构:
struct sigevent myTimerSignal = {
.sigev_notify = SIGEV_THREAD,
.sigev_notify_function = close //Make sure you change your function declaration to close(union sigval), you do not need to use the sigval unless you store data in your event too
};
现在创建您的计时器:
timer_t myTimer;
if(timer_create(CLOCK_REALTIME, &myTimerSignal, &myTimer)){
//An error occurred, handle it
}
允许臂,它会调用close()在一个新的线程在300秒内:
struct itimerspec timeUntilClose = {
.it_value = {
.tv_sec = 300 //300 seconds
}
};
if(timer_settime(myTimer, 0, &timeUntilClose, NULL)){
//Handle the error
}
现在,你应该准备好后经过300秒来停止程序的计时器。我知道我可能会迟到,但我希望这有助于未来的读者。
也许可以通过另一功能包住关闭功能,这将首先调用睡眠()?
到alarm
呼叫的参数是秒,而不是分钟。所以,你问应在5秒内通过主循环以后每次醒来。
下面的排序,避免问题的点解决方案,但它的工作原理。它将只我的应用程序的信号响应事件:
void close(int intSignal, siginfo_t *info, void *context)
{
// For some stupid reason MY signal doesn't populate siginfo_t
if (!info)
{
count++;
}
}
如果该SIGINFO结构是空的,这是因为报警()跳闸它。如果外线处理这样做,siginfo_t.si_pid被填入零。
我还是不喜欢这样的解决方案,但它的工作原理。现在奇怪的问题是,做一个出口(0)不关闭应用程序,虽然lighttpd的认为它的消失,并产生另一个。这意味着,现在我已经得到了胭脂的过程。 raise(SIGUSR1)
这就是应该停止FastCGI的脚本似乎并没有任何做的伎俩...嗯...
问题仍然存在:如何在一个间隔定时器做一个呼叫异步函数,而无需使用信号
?- 尝试关闭所有文件描述符(包括 stdin 和 stdout)。如果 CGI 实例空闲,这应该会关闭它。
- 您可以使用
select()
使用超时来安排而不是 SIGALRM