菜鸟随笔(3)---三种进程学习.孤儿进程.僵尸进程.守护进程

一只菜鸟横空出世,码农世界闯一闯,每天进展多一丢丢。

  

                        三种进程学习.孤儿进程.僵尸进程.守护进程

转自https://blog.csdn.net/believe_s/article/details/77040494

1、孤儿进程

如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程,这里子进程的父进程就是init进程(1号进程).其实还是很好理解的。

// 父进程先子进程退出
// 子进程会被祖父进程接手并在后台运行,执行内部的代码
int main()
{
    pid_t pid = fork();

    switch (pid)
    {
        case -1:
            perror ("fork");
            break;
        case 0:             // 子进程
            close (1);

            // 创建一个文件用来保存输出的文字
            int fd = open ("child", O_RDWR|O_CREAT, 0777);
            printf ("我是子进程,我的ID是%d\n", getpid());
            while (1)
            {
                printf ("找爸爸\n");
                fflush (stdout);
                sleep (2);
            }
            break;
        default:            // 父进程
            printf ("我是父进程:ID = %d\n", getpid());
            printf ("我走啦\n");
            while (1);
            break;
    }

    return 0;
}

 
在这里我们运行了程序,可以在另一终端看到有2个a.out在运行,我们将父进程终止,子进程并没有退出,而是在后台继续运行,并向child文件中输出文字。

2、僵尸进程 
 
如果我们了解过Linux进程状态及转换关系,我们应该知道进程这么多状态中有一种状态是僵死状态,就是进程终止后进入僵死状态(zombie),等待告知父进程自己终止,后才能完全消失.但是如果一个进程已经终止了,但是其父进程还没有获取其状态,那么这个进程就称之为僵尸进程.僵尸进程还会消耗一定的系统资源,并且还保留一些概要信息供父进程查询子进程的状态可以提供父进程想要的信息.一旦父进程得到想要的信息,僵尸进程就会结束.

// 子进程比父进程先退出
int main()
{
    int count = 5;
    while (count--)
    {
        //signal(SIGCHLD,SIG_IGN);
        pid_t pid = fork();

        switch (pid)
        {
            case -1:
                perror ("fork");
                break;
            case 0:         // 子进程
                printf ("我是子进程,我的ID是%d\n", getpid());
                printf ("我走啦\n");
                exit (0);
            default:        // 父进程
                printf ("我是父进程,我的ID是%d\n", getpid());
                //while(1);
                break;
        }
    }
    while(1);

    return 0;
}

signal(SIGCHLD,SIG_IGN);加上这行代码后僵尸进程都消失了。 
 
通过ps -ef | grep a.out 我们可以得知进程信息和进程pid,可以看到子进程就是处于defunct状态.这时我们肯定想要怎么才能避免僵尸进程呢?看程序被我注释的那句signal(SIGCHLD,SIG_IGN),加上就不会出现僵尸进程了.那我们就加点篇幅讲一下为什么就可以避免僵尸进程呢? 
这是signal()函数的声明sighandler_t signal(int signum, sighandler_t handler),我们可以得出,signal函数的第一个函数是linux支持的信号,第二个参数是对信号的操作 ,是系统默认还是忽略或捕获.我们这是就可以知道signal(SIGCHLD,SIG_IGN)是选择对子程序终止信号选择忽略,这是僵尸进程就是交个内核自己处理,并不会产生僵尸进程.

3、守护进程 
同样我们需要了解一下什么是守护进程,守护进程就是在后台运行,不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务.习惯上守护进程的名字通常以d结尾(sshd),但这些不是必须的.

下面介绍一下创建守护进程的步骤:

· 调用fork(),创建新进程,它会是将来的守护进程. 
· 在父进程中调用exit,保证子进程不是进程组长 
· 调用setsid()创建新的会话区 
· 将当前目录改成跟目录(如果把当前目录作为守护进程的目录,当前 目录不能被卸载他作为守护进程的工作目录)

// 守护进程
int daemonize (int nochdir, int noclose)
{
    // 创建子进程,关闭父进程
    pid_t pid = fork();
    if (pid > 0)        // 父进程
    {
        exit (0);
    }
    else if (pid < 0)
    {
        return -1;
    }

    // 2、设置文件的掩码,mode & ~umask
    umask (0);

    // 3、设置新的会话:脱离当前会话和终端的控制
    if (setsid() < 0)
    {
        return -1;
    }

    // 当nochdir为0时,daemon将更改进程的根目录为root
    if (0 == nochdir)
    {
        // 改变当前的工作目录
        if (chdir ("/") < 0)
        {
            return -1;
        }
    }

    // 标准输入、关闭标准输出、标准错误
    close (STDIN_FILENO);
    close (STDOUT_FILENO);
    close (STDERR_FILENO);

    if (0 == noclose)
    {
        // 重定向标准输入、关闭标准输出、标准错误
        open ("dev/null", O_RDONLY);    // 0
        open ("dev/null", O_RDWR);      // 1
        open ("dev/null", O_RDWR);      // 2
    }

    return 0;
}

int main()
{
    daemonize (0, 0);
    // daemon (0,0);          // 系统自带守护进程
    while (1);

    return 0;
}

  

原文地址:https://www.cnblogs.com/1996-1-0-3-0/p/9362391.html

时间: 2024-08-08 10:48:40

菜鸟随笔(3)---三种进程学习.孤儿进程.僵尸进程.守护进程的相关文章

Linux进程学习 - 孤儿进程和守护进程

孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如果一个子进程的父进程先于子进程 结束, 子进程就成为一个孤儿进程,它由 init 进程收养,成为 init 进程的子进程.2.那么如何让一个进程变为一个孤儿进程呢?我们可以先创建一个进程,然后杀死其父进程,则其就变成了孤儿进程.pid =  fork();if(pid > 0) {         

docker 学习笔记20:docker守护进程的配置与启动

安装好docker后,需要启动docker守护进程.有多种启动方式. 一.服务的方式 因为docker守护进程被安装成服务.所以,可以通过服务的方式启停docker守护进程,包括查看状态. sudo start docker  //启动 sudo stop docker  //停止 sudo status docker  //查看状态 二.利用docker daemon命令 sudo docker daemon 利用sudo ps -A 可以获取守护进程的进程号 三.让远程api可以访问dock

进程对象的其他方法、守护进程、使用多进程实现 socket tcp协议 server端的并发(抢票程序)、队列、进程之间的通信(IPC)

# 进程对象的其他方法 from multiprocessing import Process import time class MyProcess(Process): def __init__(self, a, b): # 为了给子进程传递参数 super().__init__() self.a = a self.b = b def run(self): print("子进程开始执行") time.sleep(2) print("子进程结束", self.a,

Shell脚本学习一:shell三种引号学习

一.Shell中变量的声明和引用 [[email protected] ~]# var1=Hello [[email protected] ~]# echo $var1 Hello [[email protected] ~]# echo ${var1}World HelloWorld 在Shell中,变量的引用使用$. 上面的代码中,$var1就是对变量var1的引用,输出的结果是Hello. 如果想链接其他字符,将变量放到大括号{}里面,然后在后面跟上其他内容. 例如上面的代码中:${var1

驱动和应用层的三种通信方式 (学习)

驱动程序和客户应用程序经常需要进行数据交换,但我们知道驱动程序和客户应用程序可能不在同一个地址空间,因此操作系统必须解决两者之间的数据交换.驱动层和应用层通信,主要是靠DeviceIoControl函数,下面是该函数的原型:BOOL DeviceIoControl ( HANDLE hDevice, // 设备句柄 DWORD dwIoControlCode, // IOCTL请求操作代码 LPVOID lpInBuffer, // 输入缓冲区地址 DWORD nInBufferSize, //

输入数字 判断正负个数 三种方式 学习笔记

import java.util.Scanner; class  TestExer{ public static void main(String[] args) { Scanner s= new Scanner(System.in); int a = 0; int b = 0; //for(;;){  for 无限循环 输入0 终止 while(true){  //for无限循环改为while无限循环 输入0终止 System.out.println("请输入一个整数"); int 

浅析三种特殊进程:孤儿进程,僵尸进程和守护进程.

其实有时想想linux内核的设计也蕴含着很多人生哲学,在linux中有这么几个特殊进程中,我们一开始见到它们的名字可能还会觉得很诧异,但在了解完了原理后,我们仔细想想,这样的命名也不无道理!下面我就给大家分别介绍一下这三种特殊的进程! 1.孤儿进程 如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程,这是子进程的父进程就是init进程(1号进程).其实还是很好理解的. #include <sys/types.h> #include <unistd.h> #inclu

Linux进程学习(孤儿进程和守护进程)

孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如果一个子进程的父进程先于子进程 结束, 子进程就成为一个孤儿进程,它由 init 进程收养,成为 init 进程的子进程.2.那么如何让一个进程变为一个孤儿进程呢?我们可以先创建一个进程,然后杀死其父进程,则其就变成了孤儿进程.pid =  fork();if(pid > 0) {         

第7章 进程关系(1)_守护、孤儿和僵尸进程

1. 守护.孤儿和僵尸进程 (1)守护进程 ①守护进程(daemon)是生存期长的一种进程.它们常常在系统引导装入时启动,在系统关闭时终止. ②所有守护进程都以超级用户(用户ID为0)的优先权运行. ③守护进程没有控制终端 ④守护进程的父进程都是init进程(1号进程). (2)孤儿进程:父进程先结束,子进程就成为孤儿进程,会由1号进程(init进程)领养. [编程实验]产生孤儿进程 //process_orphen.c #include <unistd.h> #include <std