0

ここに、シグナル処理とコピー プロセスのサンプル コードが 1 つあります。ここでは、毎秒、シグナル アクションを使用して 1 つのタイマーを呼び出したいと思います。ここでは正常に動作していますが、タイマー機能の開始と停止の間にコピープロセスコードを追加すると、最初のタイムシグナルが1秒後に発生したときにコピープロセスが強制終了されます。

ここでこれらの信号を試してみましSIGRTMAX ,SIGUSR1, SIGALRMたが、すべて同じ結果になります。

シグナルが発生したときにコピー プロセスが停止するのはなぜですか?

コード :

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>

#define SIGTIMER SIGRTMAX


timer_t KeepAliveTimerId;



void stopKeepAlive()
{
    if(KeepAliveTimerId != NULL)
    {
        timer_delete(KeepAliveTimerId);
        printf("timer delete\n");

    }
}

void  signalHandler(int signo, siginfo_t* info, void* context)
{
    if (signo == SIGTIMER)
    {
        printf("Signal Raised\n");
    }
}

int startKeepAlive()
{
    struct sigevent sigev; //signal event struct
    struct itimerspec itval;
    struct itimerspec oitval;
    struct sigaction sigact;


    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = SA_SIGINFO;
    sigact.sa_sigaction = signalHandler;

    // set up sigaction to catch signal
    if (sigaction(SIGTIMER, &sigact, NULL) == -1)
    {
        printf("time_settime error \n");
        return -1;
    }

    //Create the POSIX timer to generate signo
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = SIGTIMER;
    sigev.sigev_value.sival_int = 2;

    if (timer_create(CLOCK_REALTIME, &sigev, &KeepAliveTimerId) == 0)
     {
        itval.it_value.tv_sec = 1;
        itval.it_value.tv_nsec = 0L;
        itval.it_interval.tv_sec = itval.it_value.tv_sec;
        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;

        if (timer_settime(KeepAliveTimerId, 0, &itval, &oitval) != 0)
        {
            printf("Error in set time \n");
            return -2;
        }
    }
    else
    {
        printf("Error in creating timer \n");
        return -3;
    }
    return 0;
}


int main()
{
    int result; 
    // Start Timer
    startKeepAlive();

    result = system("cp /mnt/bct/package.QuipC /Download/ 2>&1");
    if (result == 0)
    {
        printf("result is %d\n",result);
        //stop timer
        stopKeepAlive();
        return EXIT_SUCCESS;
    }
    printf("result is %d\n",result);
    // Stop Timer
    stopKeepAlive();
   return EXIT_FAILURE;
}
4

3 に答える 3

0

私はこのコードをコンパイルしました (元の簡単なバリエーション — 明示的なvoid引数リストを追加#define _XOPEN_SOURCE 700し、宣言を取得しtimer_t、シグナル ハンドラーを簡素化し、Linux (RHEL 5) でリンクしてテストしました。Mac OS X にはヘッダーが含まれ-lrtていないためです) — より単純なコマンド (echo、sleep、echo) を実行すると、もっともらしい出力が得られます。timer_t/usr/include

Started
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Done
result is 0
timer delete

このことから、タイミング信号は によって実行されるコマンドに影響を与えないことが推測されsystem()ます。

gcc -Wall -Wextra -g -O3 -std=c99 sau.c -o sau -lrt

この-std=c99オプションは、おそらく指定する必要があることを説明しています_XOPEN_SOURCE。わざわざ でコンパイルすることができれば-std=gnu99、おそらく必要ないでしょう。

コード

#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>

#define SIGTIMER SIGRTMAX

timer_t KeepAliveTimerId;

void stopKeepAlive(void)
{
    if(KeepAliveTimerId != NULL)
    {
        timer_delete(KeepAliveTimerId);
        printf("timer delete\n");
    }
}

void  signalHandler(int signo)
{
    if (signo == SIGTIMER)
    {
        printf("Signal Raised\n");
    }
}

int startKeepAlive(void)
{
    struct sigevent sigev; //signal event struct
    struct itimerspec itval;
    struct itimerspec oitval;
    struct sigaction sigact;

    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_handler = signalHandler;

    // set up sigaction to catch signal
    if (sigaction(SIGTIMER, &sigact, NULL) == -1)
    {
        printf("time_settime error \n");
        return -1;
    }

    //Create the POSIX timer to generate signo
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = SIGTIMER;
    sigev.sigev_value.sival_int = 2;

    if (timer_create(CLOCK_REALTIME, &sigev, &KeepAliveTimerId) == 0)
     {
        itval.it_value.tv_sec = 1;
        itval.it_value.tv_nsec = 0L;
        itval.it_interval.tv_sec = itval.it_value.tv_sec;
        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;

        if (timer_settime(KeepAliveTimerId, 0, &itval, &oitval) != 0)
        {
            printf("Error in set time \n");
            return -2;
        }
    }
    else
    {
        printf("Error in creating timer \n");
        return -3;
    }
    return 0;
}

int main(void)
{
    int result; 
    // Start Timer
    startKeepAlive();

    result = system("echo Started; sleep 10; echo Done");
    if (result == 0)
    {
        printf("result is %d\n",result);
        //stop timer
        stopKeepAlive();
        return EXIT_SUCCESS;
    }
    printf("result is %d\n",result);
    // Stop Timer
    stopKeepAlive();
   return EXIT_FAILURE;
}
于 2012-05-23T15:27:46.327 に答える
0

念のため、これを追加しました:

#include <stdarg.h>
int zprintf(char *fmt, ...);
int zprintf(char *fmt, ...)
{
int rc;
char buff[100];
va_list aaa;

va_start(aaa, fmt);
rc = sprintf(buff, fmt, aaa);
va_end(aaa);

rc = write(2, buff, rc);
return rc;
}

シグナルハンドラを次のように置き換えました。

void  signalHandler(int signo, siginfo_t* info, void* context)
{
    if (signo == SIGTIMER)
    {
        zprintf("Signal Raised\n");
    }
    else
    {
        zprintf("Signal %d Raised\n", signo);
    }
}

...そして、 system() 文字列を次のように置き換えました。

result = system("cp ../wakker/megahal-9.1.1.dld/tele/megahal.brn /tmp/ 2>&1");

そしてそれはうまくいきました:

$ ./a.out
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
Signal Raised
result is 0
timer delete

偶然かもしれません。(しかし、Undefined Behavior も偶然です!)

于 2012-05-22T11:04:06.997 に答える
0

http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.htmlのリアルタイム シグナルを使用します。

... 未処理のリアルタイム シグナルのデフォルト アクションは、受信プロセスを終了することです ...

したがって、 system(...) を呼び出すと、シグナルハンドラーに何らかの影響があるようです。(wildplasser が既に述べたように) 明らかな間違い (シグナル ハンドラの printf) を取り除くことをお勧めします。上記のリンクの下には、シグナルハンドラーで使用できる関数の素晴らしいリストもあります (段落 Async-signal-safe functions)。あなたがそれをした後、それが何か違いを生んだかどうか私たちに教えてください.

于 2012-05-22T10:32:20.967 に答える