Linux系统进程编程(二)
发布时间 - 2025-07-09 00:00:00 点击率:次在前一篇文章中,我们已经对进程有了基本的认识,今天我们将继续探讨进程的实际操作——父子进程对文件的操作,以及什么是僵尸进程和孤儿进程?现在让我们揭开这些神秘的面纱!
一、父子进程对文件的操作:
1、子进程继承父进程中打开的文件:
父进程首先使用open函数打开一个文件并获得文件描述符(fd),然后通过fork函数创建子进程。之后,父子进程各自通过write函数向fd中写入内容,代码如下:
#include
#include #include #include #include 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; }
输出结果:
说明:我们可以看到,子进程继承了父进程中打开的文件,结果是接续写入(接续写入简单理解为在文件中继续写入内容)。需要注意的是,在实际测试中,有时可能只看到一个写入结果,这看起来像是分别写入,但实际上不是。因为父进程写入后立即关闭了文件,子进程就无法再写入内容。
2、父子进程各自独立打开同一文件实现共享:
现在我们将文件打开操作分别放在父进程和子进程中,看看会有什么效果,代码如下:
#include#include #include #include #include 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; }
输出结果:
说明:最终结果是分别写入。原因是父子进程在分离后各自打开了1.txt,这时这两个进程的PCB已经独立,文件表也独立,因此两次读写是完全独立的。当然,在打开文件操作时,可以通过改变open函数中的参数,使用O_APPEND来实现接续写入。这里不再举例,只需将上面的参数O_TRUNC改为O_APPEND即可。这两个参数的含义在之前的文章中已经详细介绍过。
3、小结:父进程在fork之前所做的事情对子进程有很大影响,但在fork之后,父进程在自己的if语句块中所做的事情对子进程没有影响。本质原因是fork函数内部实际上已经复制了父进程的PCB,并生成了一个新的子进程,并且在fork返回时,子进程已经完全与父进程脱离并独立由操作系统调度执行。
二、僵尸进程和孤儿进程解析:
1、什么是僵尸进程?
提到僵尸可能会让人感到有点害怕,但我们还是回到正题。在Linux系统中,我们需要理解:进程在运行时需要消耗系统资源(内存、I/O),当进程终止时,应该完全释放这些资源(如果进程终止后仍然没有释放相应资源,这些资源就会丢失)。因此,Linux系统设计时规定:每个进程退出时,操作系统会自动回收该进程涉及的所有资源(例如malloc申请的内存没有free时,当前进程结束时这些内存会被释放,open打开的文件没有close时在程序终止时也会被关闭)。然而,操作系统只回收了进程工作时消耗的内存和I/O,而没有回收进程本身占用的内存(8KB,主要是task_struct和栈内存),因为进程本身的8KB内存需要由其他进程来辅助回收。因此,每个进程都需要一个帮助其“收尸”的人,这个角色就是其父进程。所以,僵尸进程是指——子进程先于父进程结束。子进程结束后,父进程不一定立即能够帮其“收尸”,在这一段时间内(子进程已经结束且父进程尚未帮其收尸),子进程就被称为僵尸进程。下面我们来看一个演示:
#include#include #include #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; }
输出结果:
2、什么是孤儿进程?
子进程死亡需要父进程来处理,这意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没有父进程处理,这个死亡的子进程就是孤儿进程。同时,Linux系统规定:所有孤儿进程都自动成为一个特殊进程(进程1,也就是init进程)的子进程。下面我来演示一下:
#include#include #include 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; }
输出结果:
说明:这里父进程先运行并死亡,但我们后面并没有发现特殊进程init的进程ID为1,而是908,这其实与Ubuntu系统有关,实际应为1。
三、总结:
后续还会继续更新有关进程的文章,今天的学习加深了对进程的进一步理解,后面会介绍回收进程的具体实现方法。
# unix
# linux
# 操作系统
# ai
# if
# 继承
# 栈
# ubuntu
# 这两个
# 所做
# 自己的
# 的人
# 的是
# 就会
# 让人
# 放在
# 也会
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在IIS7中新建站点?详细步骤解析
Laravel怎么上传文件_Laravel图片上传及存储配置
如何在万网自助建站平台快速创建网站?
Laravel如何创建和注册中间件_Laravel中间件编写与应用流程
如何确保西部建站助手FTP传输的安全性?
英语简历制作免费网站推荐,如何将简历翻译成英文?
简历在线制作网站免费版,如何创建个人简历?
微信公众帐号开发教程之图文消息全攻略
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
Laravel如何处理异常和错误?(Handler示例)
教你用AI润色文章,让你的文字表达更专业
Laravel怎么进行浏览器测试_Laravel Dusk自动化浏览器测试入门
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
ChatGPT 4.0官网入口地址 ChatGPT在线体验官网
Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】
简单实现jsp分页
Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出
百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏
Laravel如何实现多对多模型关联?(Eloquent教程)
Laravel如何使用Gate和Policy进行授权?(权限控制)
如何在万网主机上快速搭建网站?
简单实现Android验证码
Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】
如何注册花生壳免费域名并搭建个人网站?
如何快速完成中国万网建站详细流程?
网站建设保证美观性,需要考虑的几点问题!
作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】
Windows10如何更改计算机工作组_Win10系统属性修改Workgroup
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
如何快速配置高效服务器建站软件?
Laravel如何实现API版本控制_Laravel版本化API设计方案
如何在阿里云通过域名搭建网站?
Laravel Octane如何提升性能_使用Laravel Octane加速你的应用
如何快速生成ASP一键建站模板并优化安全性?
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
网站建设要注意的标准 促进网站用户好感度!
如何在建站宝盒中设置产品搜索功能?
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】
Laravel观察者模式如何使用_Laravel Model Observer配置
Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康
独立制作一个网站多少钱,建立网站需要花多少钱?
Android自定义listview布局实现上拉加载下拉刷新功能
JS实现鼠标移上去显示图片或微信二维码
Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives
如何在阿里云高效完成企业建站全流程?
ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法
Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理


include