Наши партнеры








Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Цилюрик О.И. Linux-инструменты для Windows-программистов
Назад Библиотеки API POSIX Вперед

Модель обработки сигналов реального времени

Последняя модель - модель обработки сигналов реального времени — уже описана ранее, она определяется флагом SA_SIGINFO в структуре struct sigaction. Вот пример, в котором родительский процесс посылает дочернему «пачки» сигналов и завершается, только после чего дочерний процесс принимает сигналы; хорошо видно, что принимается вся последовательность посланных сигналов:

s5.cc :

#include "head.h" 
static void handler( int signo, siginfo_t* info, void* context ) { 
   cout << "CHILD\t[" << getpid() << ":" << getppid() << "] : " 
        << "received signal " << signo << endl; 
}; 
 int main( int argc, char *argv[] ) { 
   int opt, val, beg = _SIGMAX, num = 3, fin = _SIGMAX - num, seq = 3; 
   bool wait = false; 
   while ( ( opt = getopt( argc, argv, "b:e:n:w") ) != -1 ) { 
      switch( opt ) { 
         case 'b' : if( atoi( optarg ) > 0 ) beg = atoi( optarg ); break; 
         case 'e' : 
            if( ( atoi( optarg ) != 0 ) && ( atoi( optarg ) < _SIGMAX ) ) fin = atoi( optarg ); 
            break;
         case 'n' : if( atoi( optarg ) > 0 ) seq = atoi( optarg ); break; 
         case 'w' : wait = true; break; 
         default : 
            cout << "usage: " << argv[ 0 ] 
                 << " [-b #signal] [-e #signal] [-n #loop] [-w]" << endl;
            exit( EXIT_FAILURE ); 
            break;
      } 
   }; 
   num = fin - beg; 
   fin += num > 0 ? 1 : -1; 
   sigset_t sigset; 
   sigemptyset( &sigset ); 
   for( int i = beg; i != fin; i += ( num > 0 ? 1 : -1 ) ) sigaddset( &sigset, i ); 
   pid_t pid;
   if( pid = fork() == 0 ) { 
      // дочерний процесс: здесь сигналы обрабатываются 
      sigprocmask( SIG_BLOCK, &sigset, NULL ); 
      for( int i = beg; i != fin; i += ( num > 0 ? 1 : -1 ) ) { 
         struct sigaction act, oact; 
         sigemptyset( &act.sa_mask ); 
         act.sa_sigaction = handler; 
         act.sa_flags = SA_SIGINFO;         // вот оно - реальное время! 
         if( sigaction( i, &act, NULL ) < 0 ) perror( "set signal handler: " ); 
      }; 
      cout << "CHILD\t[" << getpid() << ":" << getppid() << "] : " 
           << "signal mask set" << endl; 
      sleep( 3 );                           // пауза для отсылки сигналов родителем 
      cout << "CHILD\t[" << getpid() << ":" << getppid() << "] : " 
           << "signal mask unblock" << endl; 
      sigprocmask( SIG_UNBLOCK, &sigset, NULL ); 
      sleep( 3 );                           // пауза для получения сигналов 
      cout << "CHILD\t[" << getpid() << ":" << getppid() << "] : " 
           << "finished" << endl; 
      exit( EXIT_SUCCESS ); 
   } 
   // родительский процесс: отсюда сигналы посылаются 
   sigprocmask( SIG_BLOCK, &sigset, NULL ); 
   sleep( 1 );                               // пауза для установок дочерним процессом 
   for( int i = beg; i != fin; i += ( num > 0 ? 1 : -1 ) ) { 
      for( int j = 0; j < seq; j++ ) { 
         kill( pid, i ); 
         cout << "PARENT\t[" << getpid() << ":" << getppid() << "] : " 
              << "signal sent: " << i << endl; 
      }; 
   }; 
   if( wait ) waitpid( pid, NULL, 0 ); 
   cout << "PARENT\t[" << getpid() << ":" << getppid() << "] : " 
        << "finished" << endl; 
   exit( EXIT_SUCCESS ); 
}; 

$ ./s5 

CHILD	[20934:20933] : signal mask set 
PARENT	[20933:5281] : signal sent: 64 
PARENT	[20933:5281] : signal sent: 64 
PARENT	[20933:5281] : signal sent: 64 
PARENT	[20933:5281] : signal sent: 63 
PARENT	[20933:5281] : signal sent: 63 
PARENT	[20933:5281] : signal sent: 63 
PARENT	[20933:5281] : signal sent: 62 
PARENT	[20933:5281] : signal sent: 62 
PARENT	[20933:5281] : signal sent: 62 
PARENT	[20933:5281] : signal sent: 61 
PARENT	[20933:5281] : signal sent: 61 
PARENT	[20933:5281] : signal sent: 61 
PARENT	[20933:5281] : finished 
$ 
CHILD	[20934:1] : signal mask unblock 
CHILD	[20934:1] : received signal 64 
CHILD	[20934:1] : received signal 64 
CHILD	[20934:1] : received signal 64 
CHILD	[20934:1] : received signal 63 
CHILD	[20934:1] : received signal 63 
CHILD	[20934:1] : received signal 63 
CHILD	[20934:1] : received signal 62 
CHILD	[20934:1] : received signal 62 
CHILD	[20934:1] : received signal 62 
CHILD	[20934:1] : received signal 61 
CHILD	[20934:1] : received signal 61 
CHILD	[20934:1] : received signal 61 
CHILD	[20934:1] : finished 

Хорошо видно, что к моменту получения сигналов, родительским процессом для получателя является процесс init (PID=1), то есть родительский процесс к этому времени уже завершился.

Более того, сигналы по схеме реального времени могут отправляться не вызовом kill(), а вызовом sigqueue(), который позволяет к сигналам, отправляемым в порядке очереди присоединять данные:

$ man sigqueue

SIGQUEUE(2)                Linux Programmer’s Manual              SIGQUEUE(2) 
NAME 
       sigqueue, rt_sigqueueinfo - queue a signal and data to a process 
SYNOPSIS 
       #include <signal.h> 
      int sigqueue(pid_t pid, int sig, const union sigval value); 
...
    union sigval { 
               int   sival_int; 
               void *sival_ptr; 
           };

Обычно указатель sival_ptr и используют для присоединения к сигналу поля данных.

Сигналы в потоках

Всё, что показано выше, относится к посылке сигналов однопоточному приложению. Модель посылки сигналов приложению из многих потоков введена POSIX 1003.b (расширение реального времени), и будет рассмотрено после рассмотрения техники потоков.


Предыдущий раздел: Оглавление Следующий раздел:
Модель надёжной обработки сигналов   Параллельные потоки