6.1 信号二、守护进程2015/7/30

信号

SIGCHLD信号处理

SIGCHLD的产生条件

子进程终止时
子进程收到SIGSTOP信号停止时
子进程处在停止态,接收到SIGCONT后唤醒时

例:

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

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

void do_sig_child(int signo)
{
    int status;
    pid_t pid;

    while ((pid = waitpid(0, &status, WNOHANG)) > 0) {  /* No blocking recycling process*/
        if (WIFEXITED(status))  /* normal exit */
            printf("child %d exit %d\n", pid, WEXITSTATUS(status));
        else if (WIFSIGNALED(status))   /* signal make quit */
            printf("child %d cancel signal %d\n", pid, WTERMSIG(status));   /* which signal */
    }   
}

int main(void)
{
    pid_t pid;
    int i;
    /* block SIGCHLD*/
    for (i=0; i<10; i++) {  //子进程,就跳出循环 父进程继续生成子进程,10次
        if ((pid = fork()) == 0)
            break;
        else if (pid < 0)
            sys_err("fork");
    }

    if (pid == 0) { 
        int n = 18;
        while (n--) {
            printf("child ID %d\n", getpid());
            sleep(1);
        }
        return i;
    }
    else if (pid > 0) {
        /* 1.set handler */
        /* 2.remove SIGCHLD block */
        struct sigaction act;

        act.sa_handler = do_sig_child;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGCHLD, &act, NULL); //if child dead,it will set SIGCHLD
        while (1) {
            printf("Parent ID %d\n", getpid());
            sleep(1);
        }
    }
    return 0;
}

信号不支持排队,当执行捕捉函数,收到多个信号时,在未决信号集里面只有一个,所以要用while循环回收。

status处理方式

pid_t waitpid(pid_t pid, int *status, int options)
    options
            WNOHANG
                没有没有子进程结束,立即返回(非阻塞)
            WUNTRACED
                如果子进程由于被停止产生的SIGCHLD, waitpid则立即返回
            WCONTINUED
                如果子进程由于被SIGCONT唤醒而产生的SIGCHLD,waitpid则立即返回
    获取status
            WIFEXITED(status)
                子进程正常exit终止,返回真
                       WEXITSTATUS(status)返回子进程正常退出值
            WIFSIGNALED(status)
                子进程被信号终止,返回真
                        WTERMSIG(status)返回终止子进程的信号值
            WIFSTOPPED(status)
                子进程被停止,返回真
                        WSTOPSIG(status)返回停止子进程的信号值
            WIFCONTINUED(status)
                子进程有停止态转为就绪态,返回真

信号中断系统调用

read阻塞时,信号中断系统调用
1.返回部分读到的数据
2.read调用失败,errno设成EINTER

守护进程

Daemon(精灵)进程,是linux中的后台服务进程,生存期较长的进程,通常独立于终端并且周期性执行某种任务或等待处理某些发生的事件

模型

守护进程编程步骤
1.创建子进程,父进程退出
所有工作在子进程中进行
形式上脱离了控制终端
2.在子进程中创建新会话
setsid()函数
使子进程完全独立出来,脱离控制
3.改变当前目录为根目录
chdir()函数
防止占用可卸载的文件系统
也可以换成其他路径
4.重设文件权限掩码
umask()函数
防止继承的文件创建屏蔽字拒绝某些权限
增加守护进程灵活性
5.关闭文件描述符0,1,2
继承的打开文件不会用到,浪费系统资源,无法卸载
6.开始执行守护进程核心工作
7.守护进程退出处理

代码模型

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

void daemonize(void)
{
    pid_t pid;
    /* *成为一个新会话的首进程,失去控制终端 */
    if((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    } else if (pid != 0) /* parent */
        exit(0);

    setsid();

    /* 改变当前工作目录到/目录下 */
    if(chdir("/") < 0) {
        perror("chdir");
        exit(1);
    }   

    /* 设置umask为0 */
    umask(0);

    /* 重定向0,1,2文件描述符到 /dev/null,因此已经失去控制终端,再操作0,1,2没有意>义*/
    close(0);
    open("/dev/null", O_RDWR);
    dup2(0, 1);
    dup2(0, 2);
}

int main(void)
{
    daemonize();
    while(1)
        sleep(1);
}

你可能感兴趣的:(6.1 信号二、守护进程2015/7/30)