#include
#include
#include
#include
static void
sig_handler( int signo )
{
printf( "getsignal\n" );
}
int
main( void )
{
sigset_t newmask,zeromask;
pid_t pid;
sigemptyset(&zeromask );
sigemptyset(&newmask );
sigaddset(&newmask, SIGUSR1 );
sigprocmask(SIG_BLOCK, &newmask, NULL); //1
signal(SIGUSR1, sig_handler );
if( (pid =fork()) == 0 )
{
sleep( 2 );
printf( "child\n" );
sigsuspend( &zeromask );
printf( "child done\n" );
exit( 0 );
}
printf("%d\n", pid );
printf("father\n" );
kill( pid,SIGUSR1 );
printf("father done\n" );
exit( 0);
}
如果省略1,则输出中子进程无child done。
添加上则有。
进程间的信号传递要用sigprocmask来阻塞(保留)信号,不然可能在sigsuspend之前传递的信号就已捕获,sigsuspend就无法返回。
#include
#include
#include
#include
static void
sig_handler( int signo )
{
printf( "getsignal\n" );
}
int
main( void )
{
sigset_t newmask,zeromask;
pid_t pid;
sigemptyset(&zeromask );
sigemptyset(&newmask );
sigaddset(&newmask, SIGUSR1 );
signal(SIGUSR1, sig_handler );
if( (pid =fork()) == 0 )
{
printf("child\n" );
sigsuspend(&zeromask );
printf("child done\n" );
exit( 0);
}
sleep( 2);
printf("father\n" );
kill( pid,SIGUSR1 );
sleep( 2);
printf("father done\n" );
exit( 0);
}
虽然用sleep可能不太适合(负载重时可能超过sleep2的时间),但忽略子进程被阻塞等延迟情况。
以上程序的输出为
child
father
get signal
child done
father done
1、程序执行,因主进程中sleep(2),执行进程切换至子进程
2、子进程输出child,并挂起,从而执行进程恢复为主进程
3、主进程如sleep(2)执行结束则输出father,并向子进程发送信号,然后子进程sleep(2),执行切换至子进程
4、 一进入子进程即捕获主进程发送的信号,输出getsignal,并从挂起退出输出 child done,子进程执行完毕
5、执行切换至主进程,sleep(2)执行结束后,输出father done,主进程执行结束。
主进程未调用kill发送信号时,执行子进程过程时没有获取到信号。
主进程在调用kill向子进程发送信号后, 相对于主进程kill发送后,执行第一条子进程中的某一语句时,子进程 即获取到信号。此时如子进程处在挂起状态,则退出挂起。
如果主进程的kill执行前,子进程已经进入pause状态,则在下一次切换到子进程时,子进程捕捉到信号并退出pause状态。
如果主进程的kill执行时,子进程还未进入pause状态,则在下一次切换到子进程时,子进程同样捕捉到信号,但是当执行到pause时,子进程便被挂起,如无信号再次传入,则无法退出挂起状态。
如果把上面程序的第一个sleep(2)去除,则程序可能会发生多种情况:
其中一种:主进程的kill发送信号后,切换至子进程时,子进程可能还没执行到sigsuspend。但此时信号已被捕获,并且sigsuspend没有能捕捉的信号,程序无childdone。
所以进程间的信号传输一般用屏蔽字阻塞,这样只有当执行sigsuspend时,此函数去除相应屏蔽字才能捕捉相应信号!(函数捕捉到信号从挂起返回时,恢复屏蔽字原值)