Unix网络编程-信号回收子进程和信号对慢系统调用的影响

信号对慢系统调用的影响

信号从接受到处理是有一个过程的,因为这个时候信号集要进内核,并从内核出来再执行信号处理函数。就可能会导致一些慢系统调用函数的假性出错(就是这个函数本身没有出错,而是由于内核执行了信号处理,才导致它出错),有些函数假错是可以重新启动的,比如说:accept,listen,read,write等;但是connect是不能重新启动的,如果对connect重连,会直接返回错误,正确的做法是关闭套接字,重新打开进行连接。

信号打断accept:
几乎所有的慢系统调用含税被信号打断,都会报一个EINTR错误,我们只要显示处理这个错误就行了。一般来讲,可以重新启动的就重新启动,不能重新启动的就再进行别的操作。

while (true)
    {
        int connect_socket;
        struct sockaddr_in client_address;
        socklen_t client_address_len = sizeof(client_address);

        // 接受连接
        connect_socket = accept(listen_socket, (struct sockaddr*)&client_address, &client_address_len);
        // 这是因为慢系统调用被信号打断,假错为EINTR,要单独判断,不是所有系统都会重启系统调用;
        // 基本所有的慢系统调用都有被信号误打断的可能, 所以要记住这一点;
        // connect不能重启,重启会直接报错,必须重新建立socket
        if (errno == EINTR) 
        {
            continue;
        }
        // 创建子进程
        pid_t pid = fork();
        if (pid < 0)
        {
            perror("fork");
            exit(-1);
        }
        if (pid == 0)    // 子进程
        {
            close(listen_socket);
            str_echo(connect_socket);
            exit(0);
        }
        // 父进程继续从就绪队列取出连接
        close(connect_socket);
    }

用于回收子进程的信号处理函数应该怎么写?

信号默认是不排队的。
也就是说:当几乎同一时刻有多个相同的信号到来的时候,可能信号处理函数只会执行一次。
这好像没什么问题,但是对下列使用信号回收子进程就会有问题:

void hander(int p)
{
    pid_t pid;
    int stat;
    pid = wait(&stat);
    printf("child %d terminated.\n", pid);
    return;
}

如果有多个客户端同时断开连接,就会同时有多个子进程关闭(变成僵尸进程),而发送的多次SIGCHLD信号,只会被执行一次,或少于应该执行的次数,这就会导致有子进程没有被收尸,变成僵尸进程。虽然僵尸进程占用的内存资源不多,但是它占用一个非常宝贵的资源——进程pid号。

正确的收尸方法:

/**
 * @brief 信号处理函数
 * 负责给断开连接的客户端的子进程收尸
 */
void hander(int p)
{
    pid_t pid;
    int stat;
    // 必须要waitpid,-1表示可以回收任何进程
    // WNOHANG表示如果没有需要回收的进程,不阻塞
    // 如果调用wait,只会回收一个,而信号默认是不排队的;
    // 如果同一时刻大量信号涌来,信号处理函数就只会被执行一次,导致回收不干净
    while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
    {
        printf("child %d terminated.\n", pid);
    }
    // 正常规范要return
    return;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙子砰砰枪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值