进程详解

来源:互联网 发布:最新网络微信诈骗案例 编辑:程序博客网 时间:2024/06/04 19:53

1.守护进程:

成为守护进程的条件:
1. 守护进程必须通过创建子进行得到,创建完子进程,父进程马上退出。
2. 必须自己是会话(session)组长,setsid
3. 当前工作目录必须指向一直存在的目录。chdir(“/”);
4. 调用标准输入,标准输出和标准出错。

    close(0);    open("/dev/null", O_RDWR);    dup2(0, 1);    dup2(0,2);
1.定义:守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。2.守护进程的编程要求:    1.在后台运行。为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。 
if(pid=fork()) exit(0);//是父进程,结束父进程,子进程继续
     2. 脱离控制终端,登录会话和进程组控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响。方法是在第1点的基础上,调用setsid()使进程成为会话组长: 
setsid(); 

说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

    3. 禁止进程重新打开控制终端 现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端: 
if(pid=fork()) exit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长)
    4.关闭打开的文件描述符 为了确保调用setsid的进程不是进程组的Leader,首先fork出一个子进程,父进程退出,然后 子进程调用setsid创建新的Session,成为守护进程。按照守护进程的惯例,通常将当前工作目 录切换到根目录,将文件描述符0、 1、 2重定向到/dev/null。 Linux也提供了一个库函 数daemon(3)实现我们的daemonize函数的功能,它带两个参数指示要不要切换工作目录到根目 录,以及要不要把文件描述符0、 1、 2重定向到/dev/null    5. 改变当前工作目录 进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,写运行日志的进程将工作目录改变到特定目录如/tmpchdir("/")
#include<stdlib.h>#include<stdio.h>#include<fcntl.h>void daemonize(){     pid_t pid;     pid = fork();     if(pid < 0)     {          perror("fork");          exit(1);     }     if(pid > 0)     {          exit(0);     }     setsid();//become a session leader to lose controlling TTY     if(chdir("/") < 0)     {      perror("chdir");//change current work dir to root      exit(1);     }     close(0);     open("/dev/null",O_RDWR);     dup2(0,1);     dup2(0,2);    openlog("gq",LOG_CONS|LOG_PID,LOG_DAEMON);    syslog(LOG_INFO,"sleeping...%d..",10);}int main(){     daemonize();     while(1)     {          printf("sleeping...");          sleep(1);     } return 0;}
  1. 如果有调试信息要输出可以通过系统日志把信息输出到日志文件
/var/log/syslog    openlog("name",level);    syslog(level, "", ... );    Application 中定义level:           0: LOG_EMERG,紧急情况           1: LOG_ALERT,高优先级故障,例如数据库崩溃           2: LOG_CRIT,严重错误,例如硬件故障           3: LOG_ERR,错误           4: LOG_WARNING,警告           5: LOG_NOTICE,需要注意的特殊情况           6: LOG_INFO,一般信息           7: LOG_DEBUG,调试信息    kernel中定义level(使用printk函数设定level):           0: KERN_EMERG, 系統無法使用           1: KERN_ALERT, 必須立即執行           2: KERN_CRIT, 緊急狀態           3: KERN_ERR, 錯誤狀態           4: KERN_WARNING, 警告狀態           5: KERN_NOTICE, 正常狀態且十分重要           6: KERN_INFO, 報告           7: KERN_DEBUG, debug-level訊息

2.僵尸进程和孤儿进程:

1 什么是僵尸进程:    当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出,子进程被init接管,子进程退出后init会回收其占用的相关资源。2 怎样来清除僵尸进程:       1.改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。       2.把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。3 僵尸进程的危害:    在Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的“僵尸”进程。“僵尸”进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。由于进程表的容量是有限的,所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。4.僵尸进程的原因:     我们知道,要在当前进程中生成一个子进程,一般需要调用fork这个系统调用,fork这个函数的特别之处在于一次调用,两次返回,一次返回到父进程中,一次返回到子进程中,我们可以通过返回值来判断其返回点:
int main() {    pid_t child = fork();    if( child < 0  )    {     //fork error.        perror("fork process fail.\n");    }    else if( child ==0  )     {   // in child process        printf(" fork succ, this run in child process\n ");        return 0;    }    else {           while(1){            printf(" this run in parent process\n ");            sleep(1);        }           } }

如果子进程先于父进程退出, 同时父进程又没有调用wait/waitpid,则该子进程将成为僵尸进程。通过ps命令,我们可以看到该进程的状态为Z(表示僵死),如图所示:

  1. 避免产生僵尸进程:
    一般,为了防止产生僵尸进程,在fork子进程之后我们都要wait它们;同时,当子进程退出的时候,内核都会给父进程一个SIGCHLD信号,所以我们可以建立一个捕获SIGCHLD信号的信号处理函数,在函数体中调用wait(或waitpid),就可以清理退出的子进程以达到防止僵尸进程的目的。如下代码所示:
int main() {    pid_t child = fork();    if( child < 0  ){     //fork error.        perror("fork process fail.\n");    }    else if( child ==0  ) {   // in child process        printf(" fork succ, this run in child process\n ");        return 0;    }    else     {   wait();        while(1){            printf(" this run in parent process\n ");            sleep(1);        }           } }
6.孤儿进程:    一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程将会导致资源浪费,而孤儿则不会。

  int main() { pid_t child = fork(); if( child < 0  ) {     //fork error.  perror("fork process fail.\n"); } else if( child ==0  ) {   // in child process  sleep(6);  printf("pid = %d ppid = %d\n",getpid(),getppid());  printf(" fork succ, this run in child process\n ");  return 0; } else {   // wait(); // while(1) // {   printf(" this run in parent process\n ");   sleep(1); // } } }
0 0
原创粉丝点击