首页 > 运维 > linux运维 > 正文

Linux系统进程编程(二)

絕刀狂花
发布: 2025-07-09 11:28:10
原创
897人浏览过

在前一篇文章中,我们已经对进程有了基本的认识,今天我们将继续探讨进程的实际操作——父子进程对文件的操作,以及什么是僵尸进程和孤儿进程?现在让我们揭开这些神秘的面纱!

一、父子进程对文件的操作:

1、子进程继承父进程中打开的文件:

父进程首先使用open函数打开一个文件并获得文件描述符(fd),然后通过fork函数创建子进程。之后,父子进程各自通过write函数向fd中写入内容,代码如下:

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

int main() {
    // 首先打开一个文件
    int fd = -1;
    pid_t pid = -1;
    fd = open("1.txt", O_RDWR | O_TRUNC);
    if (fd < 0) {
        perror("open");
        exit(-1);
    }
    pid = fork();
    if (pid > 0) {
        // 父进程中
        printf("parent.\n");
        write(fd, "IOTNB", 5);
        sleep(1);
    } else if (pid == 0) {
        // 子进程
        printf("child.\n");
        write(fd, "MCU", 3);
        sleep(1);
    } else {
        perror("fork");
        exit(-1);
    }
    close(fd);
    return 0;
}
登录后复制

输出结果:

Linux系统进程编程(二)Linux系统进程编程(二)

说明:我们可以看到,子进程继承了父进程中打开的文件,结果是接续写入(接续写入简单理解为在文件中继续写入内容)。需要注意的是,在实际测试中,有时可能只看到一个写入结果,这看起来像是分别写入,但实际上不是。因为父进程写入后立即关闭了文件,子进程就无法再写入内容。

2、父子进程各自独立打开同一文件实现共享:

现在我们将文件打开操作分别放在父进程和子进程中,看看会有什么效果,代码如下:

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

int main(void) {
    // 首先打开一个文件
    int fd = -1;
    pid_t pid = -1;
    // fork创建子进程
    pid = fork();
    if (pid > 0) {
        // 父进程中
        fd = open("1.txt", O_RDWR | O_TRUNC);
        if (fd < 0) {
            perror("open");
            exit(-1);
        }
        write(fd, "IOTNB", 5);
        sleep(1);
        close(fd);
    } else if (pid == 0) {
        // 子进程
        fd = open("1.txt", O_RDWR | O_TRUNC);
        if (fd < 0) {
            perror("open");
            exit(-1);
        }
        write(fd, "MCU", 3);
        sleep(1);
        close(fd);
    } else {
        perror("fork");
        exit(-1);
    }
    return 0;
}
登录后复制

输出结果:

Linux系统进程编程(二)

说明:最终结果是分别写入。原因是父子进程在分离后各自打开了1.txt,这时这两个进程的PCB已经独立,文件表也独立,因此两次读写是完全独立的。当然,在打开文件操作时,可以通过改变open函数中的参数,使用O_APPEND来实现接续写入。这里不再举例,只需将上面的参数O_TRUNC改为O_APPEND即可。这两个参数的含义在之前的文章中已经详细介绍过。

3、小结:父进程在fork之前所做的事情对子进程有很大影响,但在fork之后,父进程在自己的if语句块中所做的事情对子进程没有影响。本质原因是fork函数内部实际上已经复制了父进程的PCB,并生成了一个新的子进程,并且在fork返回时,子进程已经完全与父进程脱离并独立由操作系统调度执行。

二、僵尸进程和孤儿进程解析:

豆包AI编程
豆包AI编程

豆包推出的AI编程助手

豆包AI编程 483
查看详情 豆包AI编程

1、什么是僵尸进程?

提到僵尸可能会让人感到有点害怕,但我们还是回到正题。在Linux系统中,我们需要理解:进程在运行时需要消耗系统资源(内存、I/O),当进程终止时,应该完全释放这些资源(如果进程终止后仍然没有释放相应资源,这些资源就会丢失)。因此,Linux系统设计时规定:每个进程退出时,操作系统会自动回收该进程涉及的所有资源(例如malloc申请的内存没有free时,当前进程结束时这些内存会被释放,open打开的文件没有close时在程序终止时也会被关闭)。然而,操作系统只回收了进程工作时消耗的内存和I/O,而没有回收进程本身占用的内存(8KB,主要是task_struct和栈内存),因为进程本身的8KB内存需要由其他进程来辅助回收。因此,每个进程都需要一个帮助其“收尸”的人,这个角色就是其父进程。所以,僵尸进程是指——子进程先于父进程结束。子进程结束后,父进程不一定立即能够帮其“收尸”,在这一段时间内(子进程已经结束且父进程尚未帮其收尸),子进程就被称为僵尸进程。下面我们来看一个演示:

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

#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main() {
    pid_t  pid;
    if((pid = fork()) == -1)
        ERR_EXIT("fork");
    else if (pid == 0) {
        printf("I am the kid,my pid : %d,my father's pid : %d!\n",getpid(),getppid());
    } else {
        while(1) {
            printf("I am the father,my pid : %d!\n",getpid());
            sleep(2);
        }
    }
    return 0;
}
登录后复制

输出结果:

Linux系统进程编程(二)

2、什么是孤儿进程?

子进程死亡需要父进程来处理,这意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没有父进程处理,这个死亡的子进程就是孤儿进程。同时,Linux系统规定:所有孤儿进程都自动成为一个特殊进程(进程1,也就是init进程)的子进程。下面我来演示一下:

#include <stdio.h>
#include <sys>
#include <unistd.h>

int main(void) {
    pid_t p1 = -1;
    p1 = fork();        // 返回2次
    if (p1 == 0) {
        // 这里一定是子进程
        // 先sleep一下让父进程先运行,先死
        sleep(1);
        printf("子进程, pid = %d.\n", getpid());
        printf("hello world.\n");
        printf("子进程, 父进程ID = %d.\n", getppid());
    }
    if (p1 > 0) {
        // 这里一定是父进程
        printf("父进程, pid = %d.\n", getpid());
        printf("父进程, p1 = %d.\n", p1);
    }
    if (p1 < 0) {
        perror("fork");
        exit(-1);
    }
    return 0;
}
登录后复制

输出结果:

Linux系统进程编程(二)

说明:这里父进程先运行并死亡,但我们后面并没有发现特殊进程init的进程ID为1,而是908,这其实与Ubuntu系统有关,实际应为1。

三、总结:

后续还会继续更新有关进程的文章,今天的学习加深了对进程的进一步理解,后面会介绍回收进程的具体实现方法。

以上就是Linux系统进程编程(二)的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号