Библиотека сайта rus-linux.net
Цилюрик О.И. 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 (расширение реального времени), и будет рассмотрено после рассмотрения техники потоков.
Предыдущий раздел: | Оглавление | Следующий раздел: |
Модель надёжной обработки сигналов | Параллельные потоки |