2

以下のコードの実行に問題があります。このコードは、getutent()を呼び出して、現在システムにログインしているユーザーの総数をカウントします。タイマーは1秒ごとに呼び出され、「isSigAlrmOccured」という名前のブール値をtrueに設定して終了します。メイン関数は、このブール値をチェックしてタイマー信号が配信されているかどうかをチェックし、ログインしているユーザーの数を監視します。残念ながら、タイマー信号はメインプログラムに正しく2回しか配信されず、それ以降はそれ以上信号を受信できません。一時停止関数の呼び出しは、最初の2つのシグナルの後で中断されることはありません。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <utmp.h>
#include <errno.h>

static int isSigAlrmOccured;

void alarm_handler (int signo)
{
  static int i=1;
  printf("\n Signal Occurred %d times\n",i++);
  isSigAlrmOccured = 1;

}

int main (int argc, char *argv[]) {
   struct itimerval delay;
   struct utmp *utmpstruct;
   int numuser;


   int ret;
   signal (SIGALRM, alarm_handler);
   delay.it_value.tv_sec = 1;
   delay.it_value.tv_usec = 0;
   delay.it_interval.tv_sec = 1;
   delay.it_interval.tv_usec = 0;
   ret = setitimer (ITIMER_REAL, &delay, NULL);
   if (ret) {
     perror ("setitimer");
     return 0;
   }
   for (;;) {
       pause ( );
       /* count the number of users */
       if ( (errno == EINTR) && (isSigAlrmOccured) ) {
           isSigAlrmOccured = 0;
           setutent();
           while ((utmpstruct = getutent())) {
           if ((utmpstruct->ut_type == USER_PROCESS) &&
               (utmpstruct->ut_name[0] != '\0'))
               numuser++;
           }
           endutent();
       }
   }
   return 0;
}

出力:

信号が1回発生しました

信号が2回発生しました

4

2 に答える 2

7

*utent() の実装は alarm() を使用しており、アラームをリセットしています。
あなたは何か他のことをしなければならないでしょう。

strace ttest (簡潔にするために一部の行を削除)
[...]
pause()
--- SIGALRM (目覚まし時計) @ 0 (0) ---
write(1, " Signal Occurred 1 times\n", 25 Signal Occurred 1回) = 25
open("/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
alarm(0) = 5
rt_sigaction(SIGALRM, {0x7f52580a91c0, [], SA_RESTORER, 0x7f5257fd46e0}, {0x40075c, [ALRM], SA_RESTORER |SA_RESTART, 0x7f5257fd46e0}, 8) = 0
アラーム(1) = 0

スリープ期間中にのみアラームを設定するサンプル コード。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <utmp.h>
#include <errno.h>

static int isSigAlrmOccured;

void alarm_handler (int signo)
{
  static int i=1;
  printf("\n Signal Occurred %d times\n",i++);
  isSigAlrmOccured = 1;

}

int main (int argc, char *argv[]) {
   struct itimerval delay;
   struct utmp *utmpstruct;
   int numuser;
   int ret;

   for (;;) {
   signal (SIGALRM, alarm_handler);
       alarm(1);       /* wake me later */
       pause ( );
       /* count the number of users */
       if ( (errno == EINTR) && (isSigAlrmOccured) ) {
       signal (SIGALRM, SIG_DFL);
           isSigAlrmOccured = 0;
           numuser = 0;
           setutent();
           while ((utmpstruct = getutent())) {
           if ((utmpstruct->ut_type == USER_PROCESS) &&
               (utmpstruct->ut_name[0] != '\0'))
               numuser++;
           }
           endutent();
           printf("found %d users\n", numuser);
       }
   }
   return 0;
}
于 2009-08-26T12:25:02.250 に答える
1

このページには、シグナル ハンドラから呼び出しても「安全」な一連の関数がリストされています。他の関数を呼び出した場合、動作は未定義です。setutent()まず第一に、それがそうではないように見えることに気づきました...

于 2009-08-26T11:51:58.890 に答える