进程间关系和守护进程

1、进程组
  每个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。通常,它们与同一作业相关联,可以接收来自同一终端的各种信号。每个进程组有一个唯一的进程组ID。每个进程组都可以有一个组长进程。组长进程的标识是,其进程组ID等于其进程ID。组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中一个进程存在,则改进程组就存在,这与其组长进程是否终止无关。
2、作业
  Shell分前后台来控制的不是进程而是作业(Job)或者进程组(Process Group)。一个前台作业可以由多个进程组成,一个后台也可以由多个进城组成,Shell可以运行一个前台作业和任意多个后台作业,这称为作业控制。
作业与进程组的区别:如果作业中的某个进程又创建了子进程,则子进程不属于作业。一旦作业运行结束,Shell就把自己提到前台(子进程还在,可是子进程不属于作业),如果原来的前台进程还存在(如果这个子进程还没终止),它自动变为后台进程组。
3、会话
  会话(Session)是一个或多个进程组的集合。这通常是登录到其上的终端设备(在终端登陆的情况下)或伪终端设备(在网络登录情况下)。建立与控制终端连接的会话首进程被称为控制进程。一个会话中的几个进程可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包括控制进程(会话首进程),一个前台进程组合任意后台进程组。

作业控制

Session与进程组“Shell可以同时运行一个前台进程和任意多个后台进程”其实是不全面的。事实上,Shell分前后台来控制的不是进程而是作业(Job)或者进程组(Process Group)。一个前台作业可以由多个进城组成,一个后台作业也可以由多个进程组成,Sell可以同时运行一个前台作业和任意多个后台作业,这曾为作业控制(Job Control)。
作业控制有关的信号
这里写图片描述
将cat放到后台运⾏,由于cat需要读标准输⼊(也就是终端输⼊),⽽后台进程是不能读终端输⼊的 ,因此内核发
SIGTTIN信号给进程,该信号的默认处理动作是使进程停⽌。
这里写图片描述
jobs命令可以查看当前有哪些作业。 fg命令可以将某个作业提⾄前台运⾏ ,如果该作业的进程组正在后台运⾏则提⾄前台运⾏,如果该作业处于停⽌状态 ,则给进程组的每个进程发 SIGCONT信号使它继续运⾏。参数 %1表⽰将第1个作业提⾄前台运⾏。 cat提到前台运⾏后,挂起等待终端输⼊,当输⼊hello并回⻋后,cat打印出同样的⼀⾏,然后继续挂起等待输⼊。如果输⼊ Ctrl-Z则向所有前台进程发 SIGTSTP信号,该信号的默认动作是使进程停⽌,cat继续以后台作业的形式存在。
bg命令可以让某个停⽌的作业在后台继续运⾏ ,也需要给该作业的进程组的每个进程发 SIGCONT信号。cat进程继续运⾏,⼜要读终端输⼊,然⽽它在后台不能读终端输⼊ ,所以⼜收到SIGTTIN信号⽽停⽌。

# kill -15 2443
# jobs
[1]+  Stopped                 cat
# fg 1
cat
Terminated

⽤kill命令给⼀个停⽌的进程发 SIGTERM(15)信号,这个信号并不会⽴刻处理 ,⽽要等进程准备继续运⾏之前处理,默认动作是终⽌进程。但如果给⼀个停⽌的进程发 SIGKILL信号就不同了。
**

守护进程

认识守护进程
  守护进程也称精灵进程( Daemon),是运⾏在后台的⼀种特殊进程。它独⽴于控制终端并且周期性地执⾏某种任务或等待处理某些发⽣的事件。守护进程是⼀种很有⽤的进程。 Linux的⼤多数服务器就是⽤守护进程实现的。⽐如,ftp服务器,ssh服务器,Web服务器httpd等。同时,守护进程完成许多系统任务。⽐如,作业规划进程crond等。
  Linux系统启动时会启动很多系统服务进程 ,这些系统服务进程没有控制终端 ,不能直接和⽤户交互。其它进程都是在⽤户登录或运⾏程序时创建 ,在运⾏结束或⽤户注销时终⽌ ,但系统服务进程(守护进程)不受⽤户登录注销的影响,它们⼀直在运⾏着。这种进程有⼀个名称叫守护进程 (Daemon)。
下⾯我们⽤ps axj命令查看系统中的进程。参数 a表⽰不仅列当前⽤户的进程 ,也列出所有其他⽤ 户的进程,参数x表⽰不仅列有控制终端的进程 ,也列出所有⽆控制终端的进程 ,参数j表⽰列出与 作业控制相关的信息。

ps axj | more

凡是TPGID⼀栏写着-1的都是没有控制终端的进程 ,也就是守护进程。
在COMMAND⼀列⽤[]括起来的名字表⽰内核线程 ,这些线程在内核⾥创建 ,没有⽤户空间代码,因此没有程序⽂件名和命令⾏ ,通常采⽤以k开头的名字,表⽰Kernel。
init进程我们已经很熟悉了 ,udevd负责维护/dev⺫录下的 设备⽂件,acpid负责电源管理,syslogd负责维护/var/log下的⽇志⽂件。
可以看出,守护进程通常采⽤以 d结尾的名字,表⽰Daemon。
创建守护进程
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并成为Session Leader。

#include<unistd.h>
pid_t setsid(void);
该函数调用成功时返回新创建的Session的id(其实也就是当前的进程id),出错返回-1

注意:调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进程组的Leader也很容易,只要先fork在调用setsid就行了。fork创建的子进程和父进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子进程中调用setsid就不会有问题了。
成功调用该函数的结果是:
创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id;
创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id;
如果当前进程原本有一个控制终端,则它数去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但知识一个普通的打开文件而不是控制终端了。
守护进程代码:

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

void mydaemon(void){
    int i;
    int fd0;
    pid_t pid;
    struct sigaction sa;
    umask(0);  //1.调用umask将文件模式创建屏蔽字设置为0
    //2.调用fork,父进程退出(exit)
    //如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕
    //保证子进程不是一个进程组的组长进程
    if((pid = fork()) < 0){
        perror("fork");
    }
    else if(pid > 0){
        exit(0);  //终止父进程
    }
    setsid();  //3.调用setsid创建一个新会话
    sa.sa_ handler = SIGCHLD;   //忽略SIGCHLD信号
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if(sigaction(SIGCHLD,&sa,NULL) < 0){   //注册子进程退出忽略信号
        return;
    }

    //注意:再次fork,终止父进程,保持子进程不是话首进程,从而保证后续不会在和其他终端关联。
    //这部分不是必须的
    if((pid = fork()) < 0){
        printf("fork error!\n");
        return;
    }
    else if(pid != 0){
        exit(0);
    }
    if(chdir("/") < 0){  //5.将当前工作目录改为根目录
        printf("child dir error\n");
        return;
    }
    //关闭不在需要的文件描述符,或者重定向到/dev/null
    close(0);
    fd0 = open("/dev/null",O_RDWR);
    dup2(fd0,1);
    dup2(fd0,2);
}

int main(){
    mydaemon();
    while(1){
        sleep(1);
    }
}   

daemon函数

#include <stdio.h>
#include <unistd.h>
int main()
{
    daemon(0,0);
    while(1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值