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