c альтернатива сигналу () + сигнализация () - PullRequest
3 голосов
/ 12 октября 2009

Я создаю несколько приложений FastCGI, и мне кажется, что lighttpd не убивает их после того, как они простаивают, поэтому я пытаюсь их закрыть самостоятельно.

Я пытался использовать

signal(SIGALRM, close);
alarm(300);

и с функцией закрытия выполнить 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);
}

Ответы [ 6 ]

2 голосов
/ 12 октября 2009

лучший способ: добавить поток, чтобы вы могли удалить сигнал и аварийный сигнал, и синхронизировать поток и ваш основной код (основной поток).

1 голос
/ 12 декабря 2017

Я бы, наверное, использовал таймеры 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 секунд. Я знаю, что могу опоздать, но надеюсь, что это поможет будущему читателю.

0 голосов
/ 12 октября 2009

Вот решение, которое как бы избегает сути вопроса, но оно работает. Он будет реагировать только на сигнальные события моего приложения:

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 заполняется нулями.

Мне все еще не нравится это решение, но оно работает. Странная проблема сейчас в том, что выход (0) не закрывает приложение, хотя lighttpd считает, что оно ушло и порождает другое. Это означает, что теперь у меня есть процессы румян. raise(SIGUSR1) что должно остановить скрипты FastCGI, похоже, тоже не помогает ... хммм ...

Все еще остается вопрос: как вызвать асинхронные функции в интервальном таймере без использования сигналов?

0 голосов
/ 12 октября 2009
  • Попробуйте закрыть все файловые дескрипторы (включая stdin и stdout). Это должно закрыть экземпляр CGI, если он простаивает.
  • Вы можете использовать select() с тайм-аутом для планирования вместо SIGALRM
0 голосов
/ 12 октября 2009

Аргументом для вызова alarm является секунд , а не минут. Итак, вы просите проснуться через 5 секунд после каждого прохождения основного цикла.

0 голосов
/ 12 октября 2009

Может быть, вы можете обернуть функцию закрытия другой функцией, которая сначала вызовет sleep ()?

...