3

我正在构建一些 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);
}
4

6 回答 6

2

最好的方法是:添加一个线程,以便您可以删除信号和警报,并同步线程和您的主代码(主线程)。

于 2009-10-12T12:52:24.903 回答
1

我可能会使用 POSIX 计时器。定时器不必使用信号。您可以选择根本不通知、发出信号或将函数作为新线程运行(我会这样做,因为它不会干扰 fastcgi)。

确保包含<signal.h>and<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
}

让我们武装它,它将在 300 秒内在一个新线程中调用 close():

struct itimerspec timeUntilClose = {
    .it_value = {
        .tv_sec = 300 //300 seconds
    }
};

if(timer_settime(myTimer, 0, &timeUntilClose, NULL)){
    //Handle the error
}

现在,您应该准备好在 300 秒后停止程序的计时器。我知道我可能会迟到,但我希望这对未来的读者有所帮助。

于 2017-12-12T04:19:46.690 回答
0

也许你可以用另一个首先调用 sleep() 的函数来包装 close 函数?

于 2009-10-11T21:07:54.720 回答
0

调用的参数alarmseconds,而不是 minutes。因此,您要求在每次通过主循环后 5 秒内被唤醒。

于 2009-10-11T21:40:02.213 回答
0
  • 尝试关闭所有文件描述符(包括标准输入和标准输出)。如果 CGI 实例空闲,这应该关闭它。
  • 您可以使用select()with timeout 来安排而不是 SIGALRM
于 2009-10-11T21:58:00.163 回答
0

这是一种避免问题重点的解决方案,但它确实有效。它只会响应我的应用程序的信号事件:

void close(int intSignal, siginfo_t *info, void *context)
{
        // For some stupid reason MY signal doesn't populate siginfo_t
        if (!info)
        {
                count++;
        }
}

如果 siginfo 结构为空,那是因为 alarm() 触发了它。如果外部进程执行此操作,则 siginfo_t.si_pid 填充为零。

我仍然不喜欢这个解决方案,但它有效。现在奇怪的问题是执行 exit(0) 不会关闭应用程序,尽管 lighttpd 认为它已经消失并产生另一个。这意味着现在我有了胭脂流程。raise(SIGUSR1)这就是应该停止 FastCGI 脚本的方法似乎也没有解决问题......嗯......

问题仍然存在:如何在不使用信号的情况下在间隔计时器上调用异步函数?

于 2009-10-11T23:01:23.083 回答