如何围绕特定进程发送信号?
How to send a signal around specific processes?
我正在尝试围绕进程循环发送信号一定次数。我的第一个参数代表我希望创建的进程数。我的第二个只是一个占位符,我目前正在启动为 0。我的第三个是我想要传递此信号的次数。我设计的流程具有这样的关系:Parent->child1,
child1->child2,child2->child3....等等。我只是想弄清楚 C,我对为什么我的代码中途停止感到困惑。它运行一两次迭代,然后停止。有人可以解释为什么吗?
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
void myHandler1 () {
if(N >= 2 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill((getpid()+1),SIGUSR1);
}
else if(N >= 2 && numOfCycles == 0) {
exit(1);
}
else if(N == 1 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill(startProcess,SIGUSR1);
}
else if(N == 1 && numOfCycles == 0) {
exit(1);
}
else {
printf("Cycle Complete\n");
exit(1);
}
}
void main(int arg, char ** argv) {
struct sigaction temp, vitas, arctic;
sigemptyset(&killSet);
sigaddset(&killSet,SIGUSR1);
N = atoi(argv[1]);
pid_t process1;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
temp.sa_handler = myHandler1;
temp.sa_flags = SA_RESTART;
// vitas.sa_handler = myHandler2;
// vitas.sa_flags = SA_NODEFER;
//
// arctic.sa_handler = myHandler3;
// arctic.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &temp, NULL);
if (N > 1 ) {
process1 = fork();
if(process1 == 0) {
if(N > 2) {
printf("I am a child with PID=%d, PPID=%d, N =%d\n",getpid(),getppid(),N);
}
N--;
char narg = N+'0';
char *pnarg = &narg;
if(startProcess == 0) {
char nstartProcess[6];
startProcess=getppid();
sprintf(nstartProcess,"%d",startProcess);
char *pstartProcess = &nstartProcess[0];
execl("circle",argv[0],pnarg,pstartProcess,argv[3],NULL);
}
else{
if(N == 1){
printf("I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
printf("\nSignal Passing start\n\n");
kill(startProcess, SIGUSR1);
while(1) {
sigsuspend(&killSet);
}
}
else {
execl("circle",argv[0],pnarg,argv[2],argv[3],NULL);
}
}
}
else {
printf("I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
wait(NULL);
while(1) {
sigsuspend(&killSet);
}
}
}
}
stalls out. Can someone explain why?
final child
没有从 sigsuspend(&killSet)
中唤醒,因为你做了 sigaddset(&killSet,SIGUSR1);
- 你似乎认为你必须将要等待的信号添加到集合中,但是相反,给定集合中的信号被阻止传递。因此,只需挂断 sigaddset
电话即可。
添加到@Armali 并且由于 sigset 不是唯一要考虑的点,提供具有更简单处理程序的实现似乎更简单并且避免 fork
+exec
,您会在评论中找到解释。我不确定我是否已经理解你的意图,从评论中我猜你正在寻找启动 N processus 最后一个发送 cycles 时间 SIGUSR1 到 parent,每个 child 进程在收到时将 SIGUSR1 发送到他们的 parent。如果我错了请纠正我。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
// Two counters for the signal handler
int numSignals=0;
int numSignalsTotal=0;
// A simple handler that do nothing else that incrementing values in the process.
// To use a SIGINFO handler : void myHandler1 (int signal, siginfo_t *info, void *ucontext) {
void myHandler1 (int signal) {
numSignals++;
numSignalsTotal++;
}
void main(int arg, char ** argv) {
struct sigaction temp;
// As Armali pointed that, here you should not add SIGUSR1 to the sigset a you want
// to suspend your process and waiting for it.
sigemptyset(&killSet);
N = atoi(argv[1]);
pid_t process1 = 0;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
// A more complete initialization here, you need to include SIGUSR1 here to associate it
// to your handler. It seems you doesn't need specific flag like SA_RESTART for it here,
// as the handler code doesn't require that.
temp.sa_handler = myHandler1;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to set handler ...");
exit(1);
}
// Instead of a mix of fork + exec, it is more simple to keep one process and fork it for each new process.
// Here, we fork at least once, the parent process will alaways be "PARENT" and have a 0 startProcess,
// the child processes will fork themselves, the parent process is their and the new forked one will be
// the next child.
while (startProcess == 0 || N > 1 ) {
process1 = fork();
// To follow the forks : printf(" Fork pid=%d %s %s %s %s\n", process1, argv[0],argv[1],argv[2],argv[3]);
if(process1 != 0 && startProcess == 0) {
// If fork() gives us a pid and we have startProcess 0, then we are the "PARENT" process.
// The only thing we have to do is waiting for signals from our childs, if there is childs.
printf(" I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
// If there's no child, we simply quit the loop.
if (N == 1) break;
// For reference, "PARENT" output what is its first child.
printf(" -> child = %d\n" , process1);
// Here, while we have cycles, we wait for signals
while(numOfCycles > 0) {
// If you use a handler, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that "PARENT" caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> PARENT : N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// We substract that from our cycles and reset numSignals
numOfCycles-=numSignals; numSignals=0;
}
// If we are here, no more cycles, so we output on STDOUT a summary of "PARENT" processing
printf(" PARENT : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// Before leaving, "PARENT" should wait for its potential remaining childs to exit
printf(" PARENT waiting for child to terminate.\n");
if (wait(NULL) == -1) {
perror("ERR: PARENt failed to wait for childs termination...");
exit(1);
}
// We quit the loop, so we exit
break;
} else {
// If only one process (N=1) was asked, nothing more to do for the fork, we quit the loop then exit
if (N == 1 && startProcess == 0) break;
// We get the parent process pid in startProcess, as we are a child process
startProcess = getppid();
// If we are the forked process, we decrement N, it will "our" N as child
if (N > 1 && process1 == 0) {
N--;
}
if(process1 == 0) {
// If we are the forked process, we simply state our identity on STDOUT, the final child should be the one with N=1
if (N > 1) {
printf(" I am a child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
} else {
printf(" I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
}
if (N == 1) {
// If we are the final child, we simply have to send SIGUSR1 signals to our parent process for the number of cycles,
// after that we simply quit the loop and exit, no more forks are required.
while(numOfCycles > 0) {
printf("\n Cycle %d, first Signal start to %d\n\n", numOfCycles--, startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: LAST CHILD : Failed to send USR1...");
exit(1);
}
}
break;
}
// Note that if we are NOT the final child, we have to go through the loop to fork a new process for the next child.
} else {
if (N > 1) {
// If we are here, we are the forked process for a child and we are not the final child.
// So we do our payload, waiting for SIGUSR1 signals from our child and sending SIGUSR1 to our parent for the
// required number of cycles.
while(numOfCycles > 0) {
// If you use a handle, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that this child caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> CHILD: N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// For each receveid signals from our child, we send one to our parent
while (numSignals > 0) {
printf("\n Signal Passing start to %d\n\n", startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: CHILD : Failed to send USR1...");
exit(1);
}
// We decrement accordingly our number of cycles and signals
numOfCycles--;
numSignals--;
}
}
// If we are here, no more cycles, so we output on STDOUT a summary of the child processing
printf(" CHILD : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// We quit the loop, so we exit, then terminate our child
break;
}
}
}
}
// We should always restore signal handler to default when we exit.
temp.sa_handler = SIG_DFL;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to restore SIGUSR1 ...");
exit(1);
}
// We output on STDOUT the related PID at each process termination.
printf(" End of PID %d\n",getpid());
}
我正在尝试围绕进程循环发送信号一定次数。我的第一个参数代表我希望创建的进程数。我的第二个只是一个占位符,我目前正在启动为 0。我的第三个是我想要传递此信号的次数。我设计的流程具有这样的关系:Parent->child1, child1->child2,child2->child3....等等。我只是想弄清楚 C,我对为什么我的代码中途停止感到困惑。它运行一两次迭代,然后停止。有人可以解释为什么吗?
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
void myHandler1 () {
if(N >= 2 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill((getpid()+1),SIGUSR1);
}
else if(N >= 2 && numOfCycles == 0) {
exit(1);
}
else if(N == 1 && numOfCycles > 0) {
printf("N=%d, numOfCycles=%d, Signal caught. PID = %d\n",N,numOfCycles,getpid());
numOfCycles--;
kill(startProcess,SIGUSR1);
}
else if(N == 1 && numOfCycles == 0) {
exit(1);
}
else {
printf("Cycle Complete\n");
exit(1);
}
}
void main(int arg, char ** argv) {
struct sigaction temp, vitas, arctic;
sigemptyset(&killSet);
sigaddset(&killSet,SIGUSR1);
N = atoi(argv[1]);
pid_t process1;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
temp.sa_handler = myHandler1;
temp.sa_flags = SA_RESTART;
// vitas.sa_handler = myHandler2;
// vitas.sa_flags = SA_NODEFER;
//
// arctic.sa_handler = myHandler3;
// arctic.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &temp, NULL);
if (N > 1 ) {
process1 = fork();
if(process1 == 0) {
if(N > 2) {
printf("I am a child with PID=%d, PPID=%d, N =%d\n",getpid(),getppid(),N);
}
N--;
char narg = N+'0';
char *pnarg = &narg;
if(startProcess == 0) {
char nstartProcess[6];
startProcess=getppid();
sprintf(nstartProcess,"%d",startProcess);
char *pstartProcess = &nstartProcess[0];
execl("circle",argv[0],pnarg,pstartProcess,argv[3],NULL);
}
else{
if(N == 1){
printf("I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
printf("\nSignal Passing start\n\n");
kill(startProcess, SIGUSR1);
while(1) {
sigsuspend(&killSet);
}
}
else {
execl("circle",argv[0],pnarg,argv[2],argv[3],NULL);
}
}
}
else {
printf("I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
wait(NULL);
while(1) {
sigsuspend(&killSet);
}
}
}
}
stalls out. Can someone explain why?
final child
没有从 sigsuspend(&killSet)
中唤醒,因为你做了 sigaddset(&killSet,SIGUSR1);
- 你似乎认为你必须将要等待的信号添加到集合中,但是相反,给定集合中的信号被阻止传递。因此,只需挂断 sigaddset
电话即可。
添加到@Armali 并且由于 sigset 不是唯一要考虑的点,提供具有更简单处理程序的实现似乎更简单并且避免 fork
+exec
,您会在评论中找到解释。我不确定我是否已经理解你的意图,从评论中我猜你正在寻找启动 N processus 最后一个发送 cycles 时间 SIGUSR1 到 parent,每个 child 进程在收到时将 SIGUSR1 发送到他们的 parent。如果我错了请纠正我。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int startProcess;
int N;
int numOfCycles;
sigset_t killSet;
// Two counters for the signal handler
int numSignals=0;
int numSignalsTotal=0;
// A simple handler that do nothing else that incrementing values in the process.
// To use a SIGINFO handler : void myHandler1 (int signal, siginfo_t *info, void *ucontext) {
void myHandler1 (int signal) {
numSignals++;
numSignalsTotal++;
}
void main(int arg, char ** argv) {
struct sigaction temp;
// As Armali pointed that, here you should not add SIGUSR1 to the sigset a you want
// to suspend your process and waiting for it.
sigemptyset(&killSet);
N = atoi(argv[1]);
pid_t process1 = 0;
startProcess = atoi(argv[2]);
numOfCycles = atoi(argv[3]);
// A more complete initialization here, you need to include SIGUSR1 here to associate it
// to your handler. It seems you doesn't need specific flag like SA_RESTART for it here,
// as the handler code doesn't require that.
temp.sa_handler = myHandler1;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to set handler ...");
exit(1);
}
// Instead of a mix of fork + exec, it is more simple to keep one process and fork it for each new process.
// Here, we fork at least once, the parent process will alaways be "PARENT" and have a 0 startProcess,
// the child processes will fork themselves, the parent process is their and the new forked one will be
// the next child.
while (startProcess == 0 || N > 1 ) {
process1 = fork();
// To follow the forks : printf(" Fork pid=%d %s %s %s %s\n", process1, argv[0],argv[1],argv[2],argv[3]);
if(process1 != 0 && startProcess == 0) {
// If fork() gives us a pid and we have startProcess 0, then we are the "PARENT" process.
// The only thing we have to do is waiting for signals from our childs, if there is childs.
printf(" I am a parent with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
// If there's no child, we simply quit the loop.
if (N == 1) break;
// For reference, "PARENT" output what is its first child.
printf(" -> child = %d\n" , process1);
// Here, while we have cycles, we wait for signals
while(numOfCycles > 0) {
// If you use a handler, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that "PARENT" caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> PARENT : N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// We substract that from our cycles and reset numSignals
numOfCycles-=numSignals; numSignals=0;
}
// If we are here, no more cycles, so we output on STDOUT a summary of "PARENT" processing
printf(" PARENT : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// Before leaving, "PARENT" should wait for its potential remaining childs to exit
printf(" PARENT waiting for child to terminate.\n");
if (wait(NULL) == -1) {
perror("ERR: PARENt failed to wait for childs termination...");
exit(1);
}
// We quit the loop, so we exit
break;
} else {
// If only one process (N=1) was asked, nothing more to do for the fork, we quit the loop then exit
if (N == 1 && startProcess == 0) break;
// We get the parent process pid in startProcess, as we are a child process
startProcess = getppid();
// If we are the forked process, we decrement N, it will "our" N as child
if (N > 1 && process1 == 0) {
N--;
}
if(process1 == 0) {
// If we are the forked process, we simply state our identity on STDOUT, the final child should be the one with N=1
if (N > 1) {
printf(" I am a child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
} else {
printf(" I am the final child with PID=%d, PPID=%d, N =%d, startProcess=%d\n",getpid(),getppid(),N,startProcess);
}
if (N == 1) {
// If we are the final child, we simply have to send SIGUSR1 signals to our parent process for the number of cycles,
// after that we simply quit the loop and exit, no more forks are required.
while(numOfCycles > 0) {
printf("\n Cycle %d, first Signal start to %d\n\n", numOfCycles--, startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: LAST CHILD : Failed to send USR1...");
exit(1);
}
}
break;
}
// Note that if we are NOT the final child, we have to go through the loop to fork a new process for the next child.
} else {
if (N > 1) {
// If we are here, we are the forked process for a child and we are not the final child.
// So we do our payload, waiting for SIGUSR1 signals from our child and sending SIGUSR1 to our parent for the
// required number of cycles.
while(numOfCycles > 0) {
// If you use a handle, you need to operate synchronously with it, so here we block SIGUSR1 as we will wait for it.
if (sigprocmask(SIG_BLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to block usr1...");
exit(1);
}
// We wait for a SIGUSR1.
sigsuspend(&killSet);
// We have a SIGUSR1, we unblock SIGUSR1 as we will modify numSignals and don't want handler doing that at the same time.
if (sigprocmask(SIG_UNBLOCK, &temp.sa_mask, NULL) != 0) {
perror("ERR: Failed to unblock usr1...");
exit(1);
}
// We output on STDOUT that this child caught a SIGUSR1, we should have the number of signals received in numSignals
printf(" ===> CHILD: N=%d, numOfCycles=%d, Signal caught. PID = %d, count = %d\n",N,numOfCycles,getpid(), numSignals);
// For each receveid signals from our child, we send one to our parent
while (numSignals > 0) {
printf("\n Signal Passing start to %d\n\n", startProcess);
if (kill(startProcess, SIGUSR1) != 0) {
perror("ERR: CHILD : Failed to send USR1...");
exit(1);
}
// We decrement accordingly our number of cycles and signals
numOfCycles--;
numSignals--;
}
}
// If we are here, no more cycles, so we output on STDOUT a summary of the child processing
printf(" CHILD : N=%d, PID = %d, total = %d\n",N,getpid(), numSignalsTotal);
// We quit the loop, so we exit, then terminate our child
break;
}
}
}
}
// We should always restore signal handler to default when we exit.
temp.sa_handler = SIG_DFL;
sigemptyset(&temp.sa_mask);
sigaddset(&temp.sa_mask,SIGUSR1);
temp.sa_flags = 0;
temp.sa_restorer = NULL;
// Always check that your function calls return OK. Always.
if (sigaction(SIGUSR1, &temp, NULL) != 0) {
perror("ERR: Failed to restore SIGUSR1 ...");
exit(1);
}
// We output on STDOUT the related PID at each process termination.
printf(" End of PID %d\n",getpid());
}