signal() + Alarm() の代替手段
質問
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
}
は、それが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がゼロで埋められる。
私はまだこのソリューションを好きではないが、それは動作します。奇妙な問題は、今lighttpdのは、それがなくなって考え、別のものを生成しますけれども(0)の終了を行うことは、アプリケーションを終了していないということです。これは、今私は口紅のプロセスを持っていることを意味します。どちらかのトリックを行うようには見えないのFastCGIスクリプトを停止することになっているものであるraise(SIGUSR1)
...うーん...
質問がまだ残っている:信号を使用せずにインターバルタイマに1つのコールの非同期の機能をどのように
?- すべてのファイル記述子 (stdin と stdout を含む) を閉じてみます。これにより、CGI インスタンスがアイドル状態の場合は閉じられます。
- 使用できます
select()
SIGALRM の代わりにスケジュールにタイムアウトを使用する