当前位置:网站首页>Semaphore SIGCHLD use, how to make the parent that the child performs over, how to make the distinction between multiple child processes. The end

Semaphore SIGCHLD use, how to make the parent that the child performs over, how to make the distinction between multiple child processes. The end

2022-08-09 11:27:00 XV_

本教程基于 Ubuntu 20.10 gcc 10.2.0. The sample program if you can't compile and execute normal,Your system and tools version does not match with me,请自行查阅资料.


0 概述

First presents the description of the signal:

SignalValueDescription
SIGCHLD17Child status has changed (POSIX). Signal sent to parent process whenever one of its child processes terminates or stops.See the YoLinux.com Fork, exec, wait, waitpid tutorial

参考:All signals in c/c++

意思是说,When the parent process in the process of multiple child,When a child process end or stop,Will trigger the signal processing function of the parent.

1 The parent process with a child process

先看示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

pid_t pid = 0;

void sigchld_handler(int sig){
    
    printf("father call the SIGCHLD signal handler. num = %d\n",sig);
}

int main(){
    
    signal(SIGCHLD,sigchld_handler);
    pid = fork();
    
    if(pid == -1){
    
        exit(1);
    } else if(pid == 0){
     // child code
        printf("child process is running, pid = %d.\n",getpid());       
    } else {
     // father code
        pause();
        printf("father process runs again.\n");
    }   

    return 0;
}

输出结果是

child process is running, pid = 352252.
father call the SIGCHLD signal handler. num = 17
father process runs again.

1.1 程序分析

We first analyze the program

  1. 一开始使用了signal函数,并且设置了,如果子进程结束,Is the function of the parentsigchld_handler会被触发执行.(类似于“开中断”)

  2. 父进程使用fork,Points out a child process
    在这里插入图片描述

  3. 子进程执行child code代码,父进程执行father code代码(They are concurrent execution of)
    在这里插入图片描述

  4. 如果父进程执行结束之前,子进程End of the first carried out,The child to the parent process发送信号SIGCHLD,那么,The parent will triggersignal,To perform a functionsigchld_handler,执行完该函数后,The parent process to continue the code behind the.
    在这里插入图片描述

  5. If the child process signal,父进程已经执行结束了,那么函数sigchld_handler也不会执行了,Because the parent process has been performed.
    在这里插入图片描述

这里需要特别注意的是,signal的本质是软中断,也就是中断,因此,对于Allow the signalSIGCHLDInterrupt the parent来说,在触发之前,父进程都是正常执行的,It is the same with hard interrupt!

另外这里,In fact is a higher level of abstraction of软件中断,与底层的软中断还不是一回事儿,需要明确这一点.

此外,Although it looks the interrupts areThe child is sent to the parent process的,但是实际上,是LinuxOperating system to send to the parent process,也就是说,The child process is the signal to the firstOS.Of course, you can ignore that.因为……A lot of things to go throughOS的控制的,So this has always been a concern also don't need to.

1.2 程序框架

下面来说一下,About a parent and a child process application framework.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

pid_t pid = 0;

void sigchld_handler(int sig){
    
    // Write the processing function here
}

int main(){
    
    signal(SIGCHLD,sigchld_handler);
    pid = fork();
    
    if(pid == -1){
    
        exit(1);
    } else if(pid == 0){
     // child code
        // Write the child code here 
    } else {
     // father code
        // Write the parent code here
    }   

    return 0;
}

Then respectively explain.

The first is the signal processing function

void sigchld_handler(int sig){
    
    // Write the processing function here
}

对于函数名,可以随意改,其他的不能改,函数参数只能是int类型,Parameter name can change,返回值只能是void.Content at random to write.

如果你想使用main函数中定义的参数,Only can set it to global variables.

参考:Providing/passing argument to signal handler
You can’t have data of your own passed to the signal handler as parameters. Instead you’ll have to store your parameters in global variables. (And be really, really careful if you ever need to change those data after installing the the signal handler).

But why? Now I don’t know about it.


然后说说,父进程的代码.

...
else {
     // father code
	// Write the parent code here
}  
    ...

需要注意的是,我们前面说过,If the child process to send signals the end of time,The parent process has been performed,The parent won't call signal processing function,因此,我们需要Set a thing,Ensure that the child at the end of the,The parent must be not performed,Of course, you must know,这Just for the teaching purpose,让你看见,The parent's will call signal processing function.Real case no need to wait.

所以说,What can be added?理论来说,And what actually is ok,Just let the parent processLocal slowly就好了.

举例

else {
     // father code
	sleep(10);
	// Write the parent code here
} 

Below I just,sleep(10)What can replace the position.

1. pause();
2. wait(NULL);
3. for循环999999994. ...

这些都可以,不过,其实使用pause()就好,让程序暂停,When the trigger signal after service function,Suspended natural end,Then the parent process will perform signal processing functions,再执行其他代码.

对于for循环99999999次是不推荐的,Because the execution of the signal processing function,这个循环需要继续执行,直到结束.And it's no use value is too small,You know the execution soon,Plus it will take upCPU.

使用

wait(NULL);
pause();

是最好的,The parent will be hang wait for the child to perform the end,Then perform signal processing functions,再执行其他代码.There will be no unnecessary waiting time(对比for循环).

sleep(n);Also won't appear unnecessary waiting time,被打断后,就没了,Don't interrupt the sleep back then,This should be related to the internal implementation,但是,The number of seconds to sleep is uncertain,Who knows how long is the line process execution?So do not use this.

最安全的是wait waitpid

wait(...);
waitpid(...);

因为pause()无条件等待,这样一来,If the execution of it before,The child has been performed and call the processing function,Then performpause,The parent willAn endless waiting for.

而wait就不一样了,It identifies the child process is performed,如果没执行,Just waiting to perform finished service program;If performed before this,那就不等了,直接往下执行.(waitpid的optionParameters, please use the resulting obstruction0).

参考:Wait System Call in C

但是,有的时候pause也是很好用的,It depends,看你自己了.

Use pause function to wait a signal arrivers.

1.3 默认的信号处理函数

对于信号SIGCHLD,The default processing parametersSIG_DFL就是忽略.另外,The default processing is quite so system installed in advance processing method,You can directly invoke the default,也可以自定义,Before us is a custom.

参考
[1] IBM documentation: signal: Install signal handler
[2] signal(7) — Linux manual page

As for the details here not to say,内容比较多,Give reference links to look at oneself is good.

Also according to the results,你可以看到,Signal processing function parameterssig的值是17,也就是信号SIGCHLD的value.

2 The parent process with two child

要知道,这个信号,The parent process can be any one of its child processes to interrupt,那么,如何Identify and distinguish between multiple child process came to an end?We see the sample program

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>

pid_t fd1 = 0;
pid_t fd2 = 0;
int stat = 0;

int wd1 = 0;
int wd2 = 0;

void sigchld_handler(int sig){
    
    // represent if this function is called.
    printf("father call the SIGCHLD signal handler.\n");
   
    wd1 = waitpid(fd1,&stat,0);
    wd2 = waitpid(fd2,&stat,0);
    if(wd1 == fd1){
     // child1 finish
        printf("child1 process has finished.\n");
    }
    
    if(wd2 == fd2){
     // child2 finish
        printf("child2 process has finished.\n");
    }
}

int main(){
    
    signal(SIGCHLD,sigchld_handler);

    fd1 = fork();
    if(fd1 == -1){
    
        exit(1);
    } else if(fd1 == 0){
     // child1 code
        printf("child process is running, pid = %d.\n",getpid());       
    } else {
    
        fd2 = fork();
        switch(fd2){
    
        case -1:
            exit(1);
            break;
         case 0:// child2 code
            printf("child process is running, pid = %d.\n",getpid());   
            break;
        default: // father code
            pause();
            printf("father process runs again.\n");
            break;
        }
    }   

    return 0;
}

对于示例程序,The results may be2种情况

child process is running, pid = 375332.        
child process is running, pid = 375333.      
father call the SIGCHLD signal handler.    
child1 process has finished.         
child2 process has finished.          
father call the SIGCHLD signal handler.                                    
father process runs again.   

或者

child process is running, pid = 375332.        
child process is running, pid = 375333.      
father call the SIGCHLD signal handler.    
child1 process has finished.         
child2 process has finished.                                            
father process runs again.  

少了1个father call the SIGCHLD signal handler..

The sample program USES a rough algorithm,This way is the best,Must be able to capture or two child came to an end.

首先pause暂停父进程,如果2个子进程,One end,Will trigger the signal processing function of the parent,Then the function等着,直到2Child process all over,Will continue to execute related processing operations,此过程中,And ignored the initial trigger was a result of which the child to the end of the.

因此来说,后面的两个if语句,一定会被执行.

此时需要知道,As long as there is the child to the end,就会发送信号,Let the parent call signal handlers,因此,总体来说,Send signals must be2个,而父进程,Will receive the first signal,A second signal may not necessarily,May receive before,The parent has pulled out of the,就接收不到了.

所以才有了2Different output,Difference is a result.

参考:Signals Close Together Merge into One
If multiple signals of the same type are delivered to your process before your signal handler has a chance to be invoked at all, the handler may only be invoked once, as if only a single signal had arrived. In effect, the signals merge into one. This situation can arise when the signal is blocked, or in a multiprocessing environment where the system is busy running some other processes while the signals are delivered. This means, for example, that you cannot reliably use a signal handler to count signals. The only distinction you can reliably make is whether at least one signal has arrived since a given time in the past.

根据GNU官方的说法,Many of the same type of signal is sent to a process(在调用handler之前),These signals may be merged,也就是说,handlerMay only perform a.The details refer to the link.

As for why the call a second time,if语句块不会执行,那是因为,一旦waitpid( , ,0)执行完成,The process of waiting for is out of the,You are the second call again,返回的一定是-1了,肯定就不会执行.

最后需要知道,In the end of the parent for the child to perform again,According to the actual demand to,Now just purely for teaching.

Based on one other nature,Interrupt is random,The parent specially waiting for interrupt,It is a bit strange,But there is demand can do so.

Illustrates program just now

  1. 情况1:
    在这里插入图片描述
  2. 情况2
    在这里插入图片描述

The signal processing function,一定会被调用2次?

  • 不一定!
  • In the parent process under the premise of not the end,一定调用2次
  • The parent process end,可能调用1次或者0次
  • 因此,最多被调用2次

But will send2Time signal to the parent process!Each child at the end of the sending1次!And the parent receives the most2次!

参考:how a father process know which child process send the signal SIGCHLD

You cannot reliably use a signal handler to count signals.
在调用handler之前,Can't guarantee that the parent can receive multiple signals of the same type,This is caused by its own mechanism.因此,You can only assume,The parent received only1次信号,调用了1次hanlder,And then to do the related.


signalWhat's scope and function of aging?Multiple calls what happens?(经过测试,As at the beginning call1次就够了,即便在handler内部再调用,结果也一样,似乎它是Allows nested multiple calls的),Temporarily without access to relevant information.

原网站

版权声明
本文为[XV_]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208091103198880.html