码迷,mamicode.com
首页 > 系统相关 > 详细

终端、作业控制与守护进程

时间:2016-07-21 20:04:39      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:终端、作业控制与守护进程


进程组、作业、会话

1 进程组

   每个进程除了有一个进程ID之外,还属于一个进程组,进程组是一个或多个进程的集合。它们与同一作业相关联,可以接收来自同一终端的各种信号。只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。

2 作业

   shell分前后台来控制的不是进程而是作业(job)或者进程组;shell可以运行一个前台作业和任意多个后台作业,这称为作业控制。

   作业与进程组的区别:如果作业中的某个程序又创建了子进程,则子进程不属于作业。

3 会话

   会话是一个或多个进程组组成的集合,一个会话可以有一个控制终端。

   与控制终端关联的进程被称为控制进程

  一个会话中,应该包括控制进程(会话首进程bash),一个前台进程组和任意多个后台进程组。

终端

   在unix系统中,用户通过终端登录系统后得到一个shell进程,这个终端成为shell进程的控制终端

   每打开一个终端,就创建了一个会话,话首进程为bash

作业控制


#include<stdio.h>

int main()
{
 while(1){
  sleep(1);
  printf("hello bit\n");
 }
}

技术分享

如图:先在前台运行输出hello bit, ctrl-c停止该前台进程, 加&使该前台进程切换到后台运行,jobs查看后台作业,是标号为1的Running状态, 然后kill %1 杀死该后台进程

技术分享

前台运行该程序,ctrl-c停止前台进程,加&使该前台进程切换到后台运行,jobs查看后台作业,是标号为1的Running状态,然后fg 1又切换到前台运行,ctrl-c停止前台进程

守护进程

1、概念

   守护进程是后台进程,后台进程不一定是守护进程

   守护进程在后台运行,基本是以d结尾的;没有[ ]的是用户级别的守护进程,有[ ]的是内核级别的守护进程

    守护进程自成会话,与终端无关

2、创建守护进程

  #include<unistd.h>

   pid_t  setsid(void)

    (1)调用umask将文件模式创建屏蔽字设置为0

    (2)调用fork父进程退出,子进程(非组长进程)调用setsid;

        调用setsid后当前进程变成组长进程;当前进程变成话首进程;与控制终端脱离关系

    (3)将当前工作目录改为根目录

    (4)关闭不再需要的文件描述符

    (5)其他:忽略SIGCHLD信号

  作业:编写守护进程,回答为什么有的人创建守护进程时会fork两次?fork两次的目的是什么?

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

void creat_daemon(void)
{
 int i;
 int fd0;
 pid_t pid;
 struct sigaction sa;
 umask(0); //文件模式创建屏蔽字设置为0 

if((pid=fork())<0){
 }else if(pid!=0){
  exit(0); //终止父进程
 }
 setsid(); //设置新会话

 sa.sa_handler=SIG_IGN;
 sigemptyset(&sa.sa_mask);
 sa.sa_flags=0;

 if(sigaction(SIGCHLD,&sa,NULL)<0){ //注册子进程退出忽略信号
  return;
 }

 if((pid=fork()<0)){ //再次fork,终止父进程,保证子进程不是话首进程,从而保证后续不再和终端关联
  printf("fork error!");
  return;
 }else if(pid!=0){
  exit(0);
 }

 if(chdir("/")<0){  //更改工作目录到根目录
  printf("child dir error");
  return;
 }
 close(0);
 fd0=open("/dev/null",O_RDWR);  //关闭标准输入,重定向所有标准(输入输出错误)到/dev/null

 dup2(fd0,1);
 dup2(fd0,2);
}

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


(1)第1次fork的作用是让shell 认为本条命令已经终止,不用挂在终端输入上。还有一个作用是为了让父进程退出,因为setsid的调用者不能是组长进程. 此时父进程是组长进程。

(2)fork第二次主要目的是: 防止进程再次打开一个控制终端,因为能打开终端的只能是话首进程。再fork一次,子进程ID != sid(sid是进程父进程的sid)。所以也无法打开新的控制终端。

终端、作业控制与守护进程

标签:终端、作业控制与守护进程

原文地址:http://frankenstein.blog.51cto.com/10918184/1828514

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!