Linux系统编程——进程标识、进程创建
一、进程标识(pid)
每个进程都有一个非负整数形式的唯一编号,即 PID。PID 在任何时刻都是唯一的,但是可以重用,当进程终止并被回收以后,其 PID 就可以为其它进程所用。进程的 PID 由系统内核根据延迟重用算法生成,以确保新进程的 PID 不同于最近终止进程的 PID。
1、特殊的进程标识
0 号进程,调度进程:通常是调度进程,常常被称为交换进程(swapper)。该进程是内核的一部分,所有进程的根进程,它并不执行任何磁盘上的程序,因此也被称为系统进程。
1 号进程,init进程:通常是 init 进程,在自举过程结束时由内核调用。
2号进程,页守护进程:负责虚拟内存系统的分页操作。
2、获取进程标识
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); 返回:调用进程的进程 ID
pid_t getppid(void); 返回:调用进程的父进程 ID
uid_t getuid(void); 返回:调用进程的实际用户 ID
uid_t geteuid(void); 返回:调用进程的有效用户 ID
gid_t getgid(void); 返回:调用进程的实际组 ID
gid_t getegid(void); 返回:调用进程的有效组 ID
注意,这些函数都没有出错返回
二、进程创建(fork)和父子进程
#include <unistd.h>
pid_t fork(void);
1、函数功能
fork()主要用于以复制正在调用进程的方式去创建一个新的进程,新进程叫做子进程,原来的进程叫做父进程。
2、与fork()相关的一些问题
(1)由 fork()创建的新进程被称为子进程。fork()函数调用一次,但返回两次。两次返回的区别是:子进程的返回值是 0,而父进程的返回值则是新建子进程的进程 ID。通过fork()的返回值来区别父子进程,如果出错返回-1。
(2)调用fork()前的代码只有父进程执行,fork()成功返回后的代码,父子进程都会执行。
(3)将新建子进程 ID 返回给父进程的理由:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的 ID。
(4)fork 使子进程得到返回值 0 的理由:一个进程只会有一个父进程,所以子进程总是可以调用 getppid 以获得其父进程的进程 ID(进程 ID 0 总是由内核交换进程使用,所以一个子进程的进程 ID 不可能为 0)。
(5)调用fork()出错的原因:系统中已经存在太多的进程;调用函数fork()的用户进程太多。
3、fork()写时复制
子进程是父进程的不完全副本。子进程的数据区、bbs区、堆栈区(包括 I/O 流缓冲区),甚至参数和环境区都从父进程拷贝,唯有代码区与父进程共享。 因为,代码区是可执行指令 、字面值常量 、具有常属性且被 初始化的全局、静态全局 和 静态局部变量。
传统的fork()系统调用直接把所有的资源复制给新创建的进程,这种实现过于简单并且效率低下。Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
4、文件共享
在重定向父进程的标准输出时,子进程的标准输出也被重定向了。fork的一个特性是进程的所有打开文件描述符都被复制到子进程中。在 fork 之后处理文件描述符有以下两种常用的操作模式:
1. 父进程等待子进程完成:在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它曾进行过读、写操作的任一共享描述符的文件偏移量已做了相应更新。
2. 父进程和子进程各自执行不同的程序段:在这种情况下,在 fork 之后,父进程和子进程各自关闭它们不需使用的文件描述符,这样就不会干扰对方使用的文件描述符。这种方法是网络服务进程经常使用的。
5、父进程和子进程之间的区别
- fork 的返回值不同,子进程返回 0, 而父进程返回新建子进程 ID。
- 进程 ID 不同。
- 这两个进程的父进程 ID 不同:子进程的父进程 ID 是创建它的进程的 ID,而父进程的父进程 ID 则不变。
- 子进程的tms_utime , tms_stime , tms_cutime以及tms_ustime设置为0。
- 子进程不继承父进程设置的文件锁。
- 子进程的未处理闹钟被清除。
- 子进程的未处理信号集设置为空集。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>int main()
{pid_t pid;// fork函数被调用一次,但返回两次;在父进程中返回子进程的pid,子进程返回0pid = fork(); // 产生父子进程if (pid > 0) // 父进程执行代码段{while(1){printf("I am parent\n");printf("my pid = %d",getpid());printf("my parent pid = %d",getpid());sleep(1);}}else if (pid == 0) // 子进程执行代码段{while(1){printf("I am child\n");printf("my pid = %d",getpid());printf("my parent pid = %d",getppid());sleep(3);}}else{perror("fork"); //打印出错信息exit(1);}return 0;
}
三、fork(),vfork()和clone()的区别
1、进程四要素
- 有一段程序供其执行(不一定是一个进程所专有的),就像一场戏必须有自己的剧本。
- 有自己的专用系统堆栈空间(私有财产)。
- 有进程控制块(task_struct)(“有身份证,PID”)。
- 有独立的存储空间。
缺少第四条的称为线程,如果完全没有用户空间称为内核线程,共享用户空间的称为用户线程。
2、fork()
fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间。
3、vfork()
vfork也是创建一个子进程,但是子进程共享父进程的空间。在vfork创建子进程之后,父进程阻塞,直到子进程执行了exec()或者exit()。
vfork创建出来的不是真正意义上的进程,而是一个线程,因为它缺少第四个要素:独立的内存资源。
另外由vfork创建的子进程要先于父进程执行,子进程执行时,父进程处于挂起状态,子进程执行完,唤醒父进程。除非子进程exit或者execve才会唤起父进程。
4、clone()
clone是Linux为创建线程设计的(虽然也可以用clone创建进程)。所以可以说clone是fork的升级版本,不仅可以创建进程或者线程,还可以指定创建新的命名空间(namespace)、有选择的继承父进程的内存、甚至可以将创建出来的进程变成父进程的兄弟进程等等。
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
clone和fork最大不同在于clone不再复制父进程的栈空间,而是自己创建一个新的。 (void *child_stack)也就是第二个参数,需要分配栈指针的空间大小,所以它不再是继承或者复制,而是全新的创造。
四、孤儿进程与僵尸进程
1、父进程和子进程的关系
一个父进程可以创建多个子进程,但每个子进程最多只能有一个父进程。整个系统中只有一个根进程,即 PID 为 0 的调度进程。系统中的所有进程构成了一棵以调度进程为根的进程树。
2、父进程和子进程之间的区别
fork 的返回值不同,子进程返回 0, 而父进程返回新建子进程 ID。
进程 ID 不同
这两个进程的父进程 ID 不同:子进程的父进程 ID 是创建它的进程的 ID,而父进程的父进程 ID 则不变。
子进程的tms_utime , tms_stime , tms_cutime以及tms_ustime设置为0。
子进程不继承父进程设置的文件锁。
子进程的未处理闹钟被清除。
子进程的未处理信号集设置为空集。
3、孤儿进程
父进程创建子进程以后,子进程在操作系统的调度下与其父进程同时运行。如果父进程先于子进程终止,子进程即成为孤儿进程,同时被 init 进程收养,即成为 init 进程的子进程,因此 inti 进程又被成为孤儿院进程。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main (void)
{pid_t pid;if ((pid = fork ()) < 0)perror ("fork"), exit (1);else if (pid == 0){sleep (3); // 子进程被暂停三秒,所以当父进程退出后子进程仍然未退出。printf ("这是子进程 pid = %d", getpid ());printf ("父进程的 ppid = %d\n", getppid ());}else {printf ("这是父进程 ppid = %d\n", getpid ());}return 0;
}
4、僵尸进程
如果子进程先于父进程终止,但父进程由于某种原因,没有回收子进程的退出状态,子进程即成为僵尸进程。
僵尸进程虽然已经不再活动,但其终止状态仍然保留,也会占用系统资源,直到被其父进程回收才得以释放。
如果父进程直到终止都未回收它的已成僵尸的子进程,init 进程会立即收养并回收这些处于僵尸状态的子进程,因此一个进程不可能既是孤儿进程同时又是僵尸进程。
一个进程成为僵尸进程需要引起注意,如果它的父进程长期运行而不终止,僵尸进程所占用的资源将长期得不到释放。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main (void)
{pid_t pid;pid = fork ();if (pid == -1)perror ("fail to fork"), exit (1);else if (pid == 0){printf ("这是子进程 pid = %d", getpid ());printf ("父进程的 ppid = %d\n", getppid ());}else{// 父进程休眠了十秒,而在这期间,子进程已经退出了,//子进程就形成了一段时间的僵尸进程。sleep (10); printf ("这是父进程 ppid = %d\n", getpid ());}return 0;
}
相关文章:
Linux系统编程——进程标识、进程创建
一、进程标识(pid) 每个进程都有一个非负整数形式的唯一编号,即 PID。PID 在任何时刻都是唯一的,但是可以重用,当进程终止并被回收以后,其 PID 就可以为其它进程所用。进程的 PID 由系统内核根据延迟重用算…...
【超级福利】openMind开源实习来袭,奖励高达万元,解锁你的AI实践新篇章!
亲爱的小伙伴们,是不是梦想着能在真实的项目中大展拳脚,却又苦于找不到合适的舞台?别担心,OpenI启智社区携手openMind Library工具链,为你量身打造了一场开源实习盛宴,保证让你的学习不再无聊,技…...
React JSX 使用条件语句渲染UI的两种写法
只针对函数组件 1. 第一种写法: function App({ id }) {return id1? <h1>hello</h1> : <h1>world</h1>; } 或者: function App({ id }) {return (<h1>{id1 && "hello" || id2 && "wo…...
谷歌-BERT-第四步:模型部署
1 需求 需求1:基于gradio实现大模型的WEB UI交互界面 2 接口 3 示例 import gradio as gr from transformers import *classifier pipeline("text-classification", model"./model", tokenizer"./model")gr.Interface.from_pipel…...
猫咪化身蒲公英,浮毛满屋乱飞,有哪些宠物空气净化器值得购买?
不掉毛的猫咪究竟是谁在养? 当初去朋友家玩,被猫咪捕获芳心,没多久自己也领养了一只。没想到啊,这就意味着要和猫毛纠缠一辈子了。平时白天上班不在家,它就在一边跑动一边掉毛,回到家我都能推断它的行动路…...
端到端的开源OCR模型:GOT-OCR-2.0,支持场景文本、文档、乐谱、图表、数学公式等内容识别!
今天给大家分享一个端到端的开源 OCR 模型,号称 OCR 2.0! 支持场景文本、文档、乐谱、图表、数学公式等内容识别,拿到了 BLEU 0.972 高分。 从给出的演示图来看,一些非常复杂的数学公式都能正确的识别,颇为强大。模型…...
自注意力机制self-attention中QKV矩阵的含义
自注意力机制(Self-Attention)是Transformer模型的核心组件,其中Q、K、V矩阵分别代表查询(Query)、键(Key)、值(Value)。它们的作用和含义可以通过信息匹配过程来理解。在…...
【前端】Bootstrap:栅格系统 (Grid System)
Bootstrap的栅格系统是该框架的核心部分之一,能够让开发者轻松创建响应式网页布局,适配各种屏幕尺寸和设备。栅格系统通过将页面划分为12列的布局结构,开发者可以根据内容的重要性和设计需求灵活控制元素的宽度和排列。 在这篇文章中&#x…...
一文读懂,SSL证书怎么验签安装使用?
SSL证书目前已经有越来越多的企业网站开始使用,安装SSL证书后,原有的http协议将会变成安全性更好的https加密协议,这对保护用户的信息安全,保障企业及用户的利益起着重要作用。 一张SSL证书的获取,需要经历不少环节&a…...
Mysql(八) --- 视图
文章目录 前言1.什么是视图?2.创建视图3. 使用视图4. 修改数据4.1.注意事项 5. 删除视图6.视图的优点 前言 前面我们学习了索引,这次我们来学习视图 1.什么是视图? 视图是一个虚拟的表,它是基于一个或多个基本表或其他视图的查询…...
SQL注入原理、类型、危害与防御
SQL注入的原理概念 SQL注入是一种常见的网络攻击技术,攻击者通过在Web应用程序的输入字段中注入恶意构造的SQL代码,以欺骗后端数据库执行非预期的SQL命令。这种攻击可以导致数据泄露、权限提升、数据篡改甚至系统瘫痪。SQL注入可以分为多种类型…...
第2讲 数据库系统的结构抽象与演变
基本内容 数据库系统的标准结构?数据模型?数据库系统的演变与发展?重难点 一组概念的区分:三级模式两层映像,物理独立性和逻辑独立性一组概念的区分:数据→模式→数据模型几种数据模型的差异:网状/层次模型→关系模型→数据模型数据库系统的标准结构 (1)数据库系统的分…...
Git创建开发分支命名规则
git checkout -b feature/branchname 和 git checkout -b branchname 这两条命令的主要区别在于新分支的命名。 主要区别 分支命名: git checkout -b feature/branchname:新分支的名字是 feature/branchname,表示该分支属于一个特性开发&…...
【纯前端excel导出】vue2纯前端导出excel,使用xlsx插件,修改样式、合并单元格
一、使用第三方插件 1、安装 npm install xlsx-js-style 2、引入 import xlsx from xlsx-js-style xlsx插件是基础的导出,不可以修改样式,直接xlsx-style插件式修改样式的,所以这里直接用二者合体插件即可 二、页面使用 1、数据源 [{"…...
如何在极速浏览器中实现谷歌浏览器的扩展功能
在当今数字化时代,浏览器扩展功能极大地增强了我们的在线体验。尤其是谷歌浏览器,以其丰富的扩展生态而闻名。但是,如果你想在极速浏览器中使用这些谷歌浏览器的扩展功能,该怎么办呢?本文将为你详细解析如何实现这一目…...
Web安全 - 跨站点请求伪造CSRF(Cross Site Request Forgery)
文章目录 OWASP 2023 TOP 10CSRF 导图CSRF的基本概念CSRF的工作原理常见CSRF攻击模式CSRF防御策略补充建议应用场景实战防御策略选择1. CSRF Token(首选)2. SameSite Cookie属性3. 验证Referer和Origin4. 多因素认证 实现方案CSRF Token实现SameSite Coo…...
C++游戏开发完整学习路径
C游戏开发完整学习路径 引言 随着游戏行业的迅速发展,C作为主要的游戏开发语言,因其高效性和灵活性,依然受到广泛欢迎。C不仅在大型游戏开发中被广泛使用,而且在游戏引擎的构建、性能优化和复杂算法的实现中也扮演着关键角色。本…...
vue3之 shallowRef、markRaw
shallowRef 用于创建一个浅层响应式引用,只对顶层属性进行响应式处理。 markRaw 用于标记一个对象,使其完全跳过 Vue 的响应式系统。 这两者都可以用于优化性能,避免不必要的响应式开销,特别是在处理大型对象或第三方库对象时。 …...
影刀RPA实战:操作Mysql数据库
1.摘要 影刀RPA(Robotic Process Automation)是一种软件自动化工具,它可以模拟人类用户执行各种重复性任务,其中包括对数据库的操作。 我们可以使用软件自动化指令,通过获取数据库窗口对象来操作数据库,也…...
【c++】c++11多线程开发
2 C多线程 本文是参考爱编程的大丙c多线程部分内容,按照自己的理解对其进行整理的一篇学习笔记,具体一些APi的详细说明请参考大丙老师教程。 代码性能的问题主要包括两部分的内容,一个是前面提到资源的获取和释放,另外一个就是多…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...


