我需要将父进程和子进程同步以无限循环的顺序工作,但过了一段时间我就陷入僵局。
我不允许使用睡眠,等待,我必须实现与信号的同步。搜索后我找到了一个类似的问题,使用了暂停方法,在答案中建议使用sigsuspend而不是暂停。所以我不确定我的实现是否存在问题,或者我需要使用其他方法来避免死锁
继承我的代码
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
void catcher( int sig ) {
printf( "inside catcher() function\n" );
}
void timestamp( char *str ) {
time_t t;
time( &t );
printf( "%s the time is %s\n", str, ctime(&t) );
}
int main( int argc, char *argv[] ) {
struct sigaction sigact;
sigset_t block_set1,block_set2;
sigfillset( &block_set1 );
sigfillset( &block_set2 );
sigdelset( &block_set1, SIGUSR1 );
sigdelset( &block_set2, SIGUSR2 );
sigemptyset( &sigact.sa_mask );
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction( SIGUSR1, &sigact, NULL );
sigaction( SIGUSR2, &sigact, NULL );
pid_t child_id;
child_id = fork ();
if (child_id == 0){
while(1){
printf("child send signal\n");
kill (getppid (), SIGUSR1);
printf("child wait signal\n");
sigsuspend( &block_set2 );
printf("child is going to die\n");
}
}else{
while(1){
timestamp( "before sigsuspend()" );
sigsuspend( &block_set1 );
timestamp( "after sigsuspend()" );
kill (child_id, SIGUSR2);
printf("parent is going to die\n");
}
}
return( 0 );
}
答案 0 :(得分:0)
这个程序有一个问题,考虑一下子/父在使用sigsuspend()暂停执行之前向父/子发送信号的情况。在这种情况下,处理程序将被执行,之后将不会有人 他们打断sigsupend()可能会导致无限暂停状态。
引用手册页
int sigsuspend(const sigset_t * mask);
sigsuspend()暂时替换调用的信号掩码 使用掩码给出的掩码处理,然后暂停该过程 直到传递其动作是调用信号处理程序的信号 或者终止一个过程。
我建议改用sigwaitinfo(),
int sigwaitinfo(const sigset_t * set,siginfo_t * info);
sigwaitinfo()暂停执行调用线程,直到其中一个 set中的信号处于待处理状态(如果已设置其中一个信号 等待调用线程,sigwaitinfo()将返回 立即。)
请找到相同的示例程序。
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
void timestamp( char *str ) {
time_t t;
time( &t );
printf( "%s the time is %s\n", str, ctime(&t) );
}
int main( int argc, char *argv[] ) {
sigset_t parent_set, child_set;
sigset_t set;
siginfo_t info;
/*Mask SIGUSR2 and SIGUSR1 signal, you can choose this mask
* according to your requirement*/
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
sigprocmask(SIG_SETMASK, &set, NULL);
sigemptyset(&child_set);
sigaddset(&child_set, SIGUSR2);
sigemptyset(&parent_set);
sigaddset(&parent_set, SIGUSR1);
pid_t child_id;
child_id = fork ();
if (child_id == 0){
while(1){
printf("child send signal\n");
kill (getppid (), SIGUSR1);
printf("child wait signal\n");
/* Child will suspend its execution if parent did not notify it
* using signal(SIGUSR2), if parent has already notified sigwaitinfo()
* will return immediately
**/
sigwaitinfo(&child_set, &info );
printf("child is going to die\n");
}
}else{
while(1){
timestamp( "before sigwaitinfo()" );
/* Parent will suspend its execution if child did not notify it
* using signal(SIGUSR1), if child has already notified sigwaitinfo()
* will return immediately
**/
sigwaitinfo(&parent_set, &info );
timestamp( "after sigwaitinfo()" );
kill (child_id, SIGUSR2);
printf("parent is going to die\n");
}
}
}
我希望这会对你有所帮助。
答案 1 :(得分:0)
问题,就像@monc noted一样,当另一个过程尚未准备好时,一个过程会向另一个过程发出信号。
因此,在调用sigaction()
之前传递信号(即调用sigsuspend()
处理程序),因此传递不能中断sigsuspend()
。这样的事情发生了:
while(1){
printf("child send signal\n");
kill (getppid (), SIGUSR1);
// SIGUSR2 delivered here
printf("child wait signal\n"); // or here
// or here
sigsuspend( &block_set2 ); // wait forever...
...
}
解决方案是从一开始就阻止(掩码)父级中的SIGUSR1和子级中的SIGUSR2。阻止信号将阻止传递,保持它们等待直到sigsuspend()
原子地交换信号掩码以允许传递(和中断)。为了安全起见,在调用fork()
之前应该阻止信号,孩子可以从父母那里继承信号掩码:
sigemptyset(&ss);
sigaddset(&ss, SIGUSR1);
sigaddset(&ss, SIGUSR2);
sigprocmask(SIG_BLOCK, &ss, NULL);
... fork();
// child
while (1) {
sigset_t wakemask;
sigemptyset(&wakemask);
...
sigsuspend(&wakemask);
}
// similarly for parent ...
请注意,在上面,父和子都阻止了两个信号,包括它们相互发送的信号。这没有必要 - 您可以在fork()
之后立即解锁 - 但也无害。
此外,您还可以使用sigwait
系列函数接受而不是传递信号。在这种情况下,您不需要使用sigaction
设置处理程序,但仍需要阻止信号。