根据发布的功能,我认为您的代码中有两个主要问题。
1. 在每次调用信号处理程序时关闭文件描述符。
这不是一个好主意 - 每次在读取或写入后关闭文件描述符。单向管道不能以这种方式工作。创建描述符对后,您应该在一个进程中关闭第一个描述符,在另一个进程中关闭第二个描述符。这将创建一个从第一个进程到第二个进程的管道(man pipe)。在手册页的示例中,他们在写入后立即关闭描述符,因为他们不再需要它。
2. 好像你只有 3 对文件描述符。
通过单向管道连接 3 个进程(如下图所示),需要 6 对描述符:
fd 5,6
+------------+ +------------+
| |<----------| |
| process #0 | | process #1 |
| |---------->| |
+------------+ +------------+
| ^ fd 7,8 | ^
| | | |
fd 1,2 | | fd 3,4 fd 9,10 | | fd 11,12
| | | |
v | | |
+------------+ | |
| |<--------------+ |
| process #2 | |
| |-------------------+
+------------+
例子。
这是一个代码示例,它做同样的事情。它与好的示例相去甚远(信号处理printf
程序中的不良信号处理),但我希望它会有所帮助。
int g_pfd[3][2][2]; // pairs of file desriptors.
volatile sig_atomic_t g_ignore_sighup = 0; // flag for ignoring SIGHUP
void ( * g_handlers[3] ) ( int ); // array of signal handlers
void sig_handler ( int signo, int id )
{
if ( signo == SIGHUP )
{
if ( g_ignore_sighup )
{
g_ignore_sighup = 0;
return;
}
printf ( "SIGHUP recvd, pid = %d\n", getpid () );
int rd1 = ( id );
int rd2 = ( id == 0 ? 2 : id - 1 );
// choose, which process sent SIGHUP.
fd_set rfds;
FD_ZERO ( &rfds );
FD_SET ( g_pfd[rd1][1][0], &rfds );
FD_SET ( g_pfd[rd2][0][0], &rfds );
int rv = select ( FD_SETSIZE, &rfds, NULL, NULL, NULL );
if ( rv == -1 )
{
perror ( "select" );
return;
}
else if ( rv == 0 )
{
return;
}
int fd = -1;
if ( FD_ISSET ( g_pfd[rd1][1][0], &rfds ) ) fd = g_pfd[rd1][1][0];
if ( FD_ISSET ( g_pfd[rd2][0][0], &rfds ) ) fd = g_pfd[rd2][0][0];
int i;
if ( read ( fd, &i, sizeof ( int ) ) == -1 )
{
perror ( "read" );
}
printf ( "recvd data through pipe = %d\n", i );
return;
}
if ( signo == SIGINT )
{
int wr1 = ( id );
int wr2 = ( id == 0 ? 2 : id - 1 );
printf ( "SIGINT recvd, pid = %d\n", getpid () );
printf ( "write: %d to %d\n", getpid (), g_pfd[wr1][0][1] );
printf ( "write: %d to %d\n", getpid (), g_pfd[wr2][1][1] );
int pid = getpid ();
if ( write ( g_pfd[wr1][0][1], &pid, sizeof ( int ) ) == -1 ||
write ( g_pfd[wr2][1][1], &pid, sizeof ( int ) ) == -1 )
{
perror ( "write" );
}
g_ignore_sighup = 1; // flag for ignorig own signal
// send SIGHUP to parent and all its children.
if ( kill ( 0, SIGHUP ) == -1 )
{
perror ( "kill" );
}
return;
}
}
void sig_handler_0 ( int signo ) { sig_handler ( signo, 0 ); }
void sig_handler_1 ( int signo ) { sig_handler ( signo, 1 ); }
void sig_handler_2 ( int signo ) { sig_handler ( signo, 2 ); }
int create_process ( int *pid, int id )
{
*pid = fork ();
if ( *pid == -1 )
{
perror ( "fork" );
return 1;
}
if ( *pid != 0 ) // parent
{
return 0;
}
// close appropriate descriptors
int i1 = ( id );
int i2 = ( id == 0 ? 2 : id - 1 );
close ( g_pfd[i1][0][0] );
close ( g_pfd[i2][0][1] );
close ( g_pfd[i1][1][1] );
close ( g_pfd[i2][1][0] );
if ( signal ( SIGINT, g_handlers[id] ) == SIG_ERR ||
signal ( SIGHUP, g_handlers[id] ) == SIG_ERR )
{
perror ( "signal" );
return 1;
}
while ( 1 ) sleep ( 1 );
exit ( 0 );
}
int main ( int argc, char *argv [] )
{
// fill array of signal handlers.
g_handlers[0] = sig_handler_0;
g_handlers[1] = sig_handler_1;
g_handlers[2] = sig_handler_2;
if ( signal ( SIGHUP, SIG_IGN ) == SIG_ERR )
{
perror ( "signal" );
return 1;
}
int pid [3];
int i, j;
// create pairs of descriptors
for ( i = 0; i < 3; i++ )
{
for ( j = 0; j < 2; j++ )
{
if ( pipe ( g_pfd[i][j] ) == -1 )
{
perror ( "pipe" );
return 1;
}
}
}
if ( create_process ( &pid[0], 0 ) != 0 ||
create_process ( &pid[1], 1 ) != 0 ||
create_process ( &pid[2], 2 ) != 0 )
{
return 1;
}
sleep ( 1 );
kill ( pid[0], SIGINT ); sleep ( 3 );
kill ( pid[1], SIGINT ); sleep ( 3 );
kill ( pid[2], SIGINT );
wait ( NULL );
for ( i = 0; i < 3; i++ )
{
for ( j = 0; j < 2; j++ )
{
close ( g_pfd[i][j][0] );
close ( g_pfd[i][j][1] );
}
}
return 0;
}