したがって、毎秒「まだ機能しています...」というメッセージを表示するためにアラームを呼び出そうとしています。 signal.hを含めました。
私のメインの外に私は私の機能があります:(私はintのsを宣言/定義することはありません)
void display_message(int s); //Function for alarm set up
void display_message(int s) {
printf("copyit: Still working...\n" );
alarm(1); //for every second
signal(SIGALRM, display_message);
}
次に、私のメインで
while(1)
{
signal(SIGALRM, display_message);
alarm(1); //Alarm signal every second.
ループが始まるとすぐそこにあります。しかし、プログラムは「まだ機能しています...」メッセージを出力しません。何を間違っているのですか?ありがとう、verありがたいです。
シグナルハンドラーは、「ビジネスロジック」を含むことや、printf
などのライブラリー呼び出しを行うことは想定されていません。 C11§7.1.4/ 4とその脚注を参照してください。
したがって、シグナルハンドラーは、通常、標準ライブラリー関数を呼び出すことができません。
シグナルハンドラがすべきことはすべて、割り込みのないコードによって実行されるフラグを設定することです。このプログラムは正しく実行され、他のI/O機能が追加されていてもクラッシュするリスクはありません。
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
volatile sig_atomic_t print_flag = false;
void handle_alarm( int sig ) {
print_flag = true;
}
int main() {
signal( SIGALRM, handle_alarm ); // Install handler first,
alarm( 1 ); // before scheduling it to be called.
for (;;) {
if ( print_flag ) {
printf( "Hello\n" );
print_flag = false;
alarm( 1 );
}
}
}
ただし、スピンループはプログラミングの方法としてはひどいものです。この例はスリープしないため、100%のCPUパワーを使用します。さらにalarm
はC標準で定義されていないようですが、POSIXはそれをそのようにマークしており、K&Rの一部であったことを思い出します。したがって、移植性に関しては、別のPOSIX機能を使用することもできます。
signal
およびalarm
への呼び出しをループの直前に移動します。高速でalarm
を繰り返し呼び出すと、その時点から1秒以内にアラームがリセットされ続けるため、その秒の終わりに到達することはありません。
例えば:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void display_message(int s) {
printf("copyit: Still working...\n" );
alarm(1); //for every second
signal(SIGALRM, display_message);
}
int main(void) {
signal(SIGALRM, display_message);
alarm(1);
int n = 0;
while (1) {
++n;
}
return 0;
}
alarm()
呼び出しは、1回限りの信号用です。
アラームを繰り返すには、信号が発生するたびにalarm()
を再度呼び出す必要があります。
ただし、次のSIGALRM
を待つ正しい方法は、pause()
関数を使用することです。他の人が言及していないもの(代わりに、タイトなループがあり、醜い!)
そうは言っても、次のような単純なsleep()
呼び出しを使用すると、実行しようとしていることがはるかに簡単になります。
_// print a message every second (simplified version)
for(;;)
{
printf("My Message\n");
sleep(1);
}
_
注:sleep()
関数は実際にはalarm()
と同じタイマーを使用して実装されており、同じコードで両方の関数を混在させないでください。
sleep(3)
はSIGALRM
を使用して実装できます。alarm()
とsleep(3)
の呼び出しを混在させることはお勧めできません。
(Linuxから_man alarm
_)
_void alarm_handler(int)
{
alarm(1); // recurring alarm
}
int main(int argc, char *argv[])
{
signal(SIGALRM, alarm_handler);
alarm(1);
for(;;)
{
printf("My Message\n");
// ...do other work here if needed...
pause();
}
// not reached (use Ctrl-C to exit)
return 0;
}
_
バリエーションを作成できます。たとえば、最初のメッセージをすぐにではなく1秒後に発生させる場合は、pause()
の前にprintf()
を移動します。
「他の仕事」のコメントは、あなたの他の仕事が1秒を超えないことを前提としています。
並列処理が必要な場合、特定のスレッドでアラーム信号を取得することは可能ですが、他のタイマーが必要な場合は複雑になる可能性があります(つまり、alarm()
タイマーを他のタイマーと簡単に共有することはできません)関数。)
追伸他の人が述べたように、シグナルハンドラ内でprintf()
を実行することは、まったく良い考えではありません。
alarm()
がmain()
内でリセットされ、1秒後に最初のメッセージが表示され、ループが60秒(1分)実行される別のバージョンがあります。
_void alarm_handler(int)
{
}
int main(int argc, char *argv[])
{
signal(SIGALRM, alarm_handler);
for(int seconds(0); seconds < 60; ++seconds)
{
alarm(1);
// ...do other work here if needed...
pause();
printf("My Message\n");
}
// reached after 1 minute
return 0;
}
_
この方法では、メッセージが印刷される時間がずれることに注意してください。アラームを再開する前に、メッセージを印刷する時間が時計に追加されます...そのため、各呼び出しの間隔は常に1秒強です。他のループはその点でより優れていますが、それでも歪んでいます。 perfect(はるかに優れた)タイマーの場合、poll()
関数は、次に起動するタイミングを指定できるため、はるかに優れています。 poll()
は、タイマーでのみ使用できます。私の スナップライブラリ はその機能を使用します(ファイルの下部近くにあるrun()
関数を探します)。
US Naval Academyからもいくつかの アラームおよびその他の信号コードサンプル があります。
alarm()
を2回呼び出さないでください。コールバックを開始するためにmain()
で1回呼び出してから、display_message()
で1回呼び出すだけです。 Linux(Debian 7.8)でこのコードを試してください:
#include <stdio.h>
#include <signal.h>
void display_message(int s); //Function for alarm set up
void display_message(int s)
{
printf("copyit: Still working...\n" );
alarm(1); //for every second
signal(SIGALRM, display_message);
}
int main()
{
signal(SIGALRM, display_message);
alarm(1); // Initial timeout setting
while (1)
{
pause();
}
}
結果は次のようになります。
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...
copyit: Still working...