进程系统调用
进程系统调用
文章目录
- 进程系统调用
- fork()
- 进程创建:fock()
- fork函数
- fork用法
- 僵尸进程
- 孤儿进程
- vfork函数
- vfork与fork区别
- exec函数族
- exec函数族-何时使用?
- exec函数族语法
- exec函数族使用区别
- exit和_exit
- _exit和exit的区别
- wait和waitpid
fork()
进程创建:fock()
#include <sys/types.h> // 提供类型pid_t的定义
#include <unistd.h>pid_t fork(void);
函数返回值
0: 子进程
子进程PID(大于0的整数):父进程
-1: 出错
#include <unistd.h>
#include <stdio.h>int main(){pid_t pid;if((pid=fork())==-1){perror("fork");return -1;}else if(pid == 0){printf("child 子进程\n");printf("child process %d,pid = %d,ppid = %d\n",pid,getpid(),getppid());}else{printf("parent 父进程\n");printf("parent process %d,pid = %d,ppid = %d\n",pid,getpid(),getppid());}return 0;
}
fork()执行后当前进程会被克隆一遍,克隆之后子进程会有一个与原来相同的代码,父进程与子进程之间是独立调度的,即操作系统独立调度父进程和子进程,先调度谁,后调度谁有一定随机性,此处先调度了父进程,父进程看到的是子进程的pid,3518,然后父进程打印自己的pid和ppid,父进程运行完之后进程结束了,操作系统接着调度子进程,调度子进程的时候,也从fork()返回,但子进程看到的pid是0,所以子进程打印else内容,然后打印自己的pid和ppid
#include <unistd.h>
#include <stdio.h>int main(){pid_t pid;if((pid=fork())==-1){perror("fork");return -1;}else if(pid == 0){printf("child 子进程\n");printf("child process %d,pid = %d,ppid = %d\n",pid,getpid(),getppid());子进程逻辑}else{printf("parent 父进程\n");printf("parent process %d,pid = %d,ppid = %d\n",pid,getpid(),getppid());父进程逻辑}return 0;
}
fork函数
使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:
进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。
子进程与父进程的区别在于:
1、父进程设置的锁,子进程不继承(因为如果是排它锁,被继承的话,矛盾了)
2、各自的进程ID和父进程ID不同
3、子进程的未决告警被清除;
4、子进程的未决信号集设置为空集
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int glob = 6;
int main()
{int local;int pid;local = 88; printf("parent[pid = %d]: before fork, glob(&glob) = %d(%p), local(&local) = %d(%p)\n",getpid(), glob, &glob, local, &local );if((pid = fork()) < 0) {perror("fail to fork");return -1; } if(pid == 0) { /* child process */printf("child[pid = %d]: after fork, glob(&glob) = %d(%p), local(&local) = %d(%p)\n",getpid(), glob, &glob, local, &local );glob++;local++; printf("child[pid = %d]: changed data after fork, glob(&glob) = %d(%p), local(&local) = %d(%p)\n",getpid(), glob, &glob, local, &local );}else { /* parent process */sleep(2);printf("parent[pid = %d]: after fork, glob(&glob) = %d(%p), local(&local) = %d(%p)\n",getpid(), glob, &glob, local, &local );} /* return euqal to exit(0), but exit may cause a compile warning* due to main() is declared to return with an integter */return 0;
}
注意
sleep(2)
目的防止父进程先执行,实现两个进程间的同步
虚拟地址相同,但实际物理地址不相同,所以修改后,父进程中变量的值没有被修改
该代码演示了fork函数的使用,fork函数可以复制一个新进程,并在新进程和原进程中运行不同的代码。下面是代码的详细分析:
- 包含需要的头文件:stdio.h,stdlib.h和unistd.h。
- 声明全局变量glob,并初始化为6。
- 定义main函数。
- 声明一个名为local的整型变量。
- 将变量local初始化为88。
- 打印出父进程的进程ID、全局变量glob的值和地址,以及变量local的值和地址。
- 如果fork函数返回值小于0,则表示fork失败,打印出错误信息并返回-1。
- 如果fork函数返回值等于0,则表示当前代码在子进程中运行。打印出子进程的进程ID、全局变量glob的值和地址,以及变量local的值和地址。
- 在子进程中,全局变量glob的值加1,变量local的值加1。
- 在子进程中,打印出子进程修改后的全局变量glob的值和地址,以及变量local的值和地址。
- 如果fork函数返回值大于0,则表示当前代码在父进程中运行。
- 在父进程中,调用sleep函数暂停2秒,以等待子进程修改变量。
- 在父进程中,打印出父进程修改前的全局变量glob的值和地址,以及变量local的值和地址。
- 最后,在主函数中返回0。
根据代码运行结果,可以看出:
-
父进程在调用fork函数之前,输出了全局变量glob和变量local的值和地址。
-
子进程在调用fork函数之后,复制了父进程的地址空间,并打印出全局变量glob和变量local的值和地址。在子进程中,这两个变量的值和地址与父进程相同。
-
子进程修改了全局变量glob和变量local的值,并打印出它们修改后的值和地址。在子进程中,这两个变量的值和地址已经发生了变化。
-
父进程在等待2秒钟后继续执行,并打印出全局变量glob和变量local的值和地址。在父进程中,这两个变量的值和地址没有发生变化。
这个结果的原因是,子进程复制了父进程的地址空间,但是子进程和父进程有不同的地址空间。因此,它们可以独立地访问和修改自己的变量。在子进程中修改全局变量和局部变量的值并不会影响父进程的值。
fork用法
僵尸进程
- 父进程 Process A 创建子进程 Process B,当子进程退出时会给父进程发送信号 SIGCHLD; 2. 如果父进程没有调用 wait 等待子进程结束,退出状态丢失,转换成僵死状态,子 进程会变成一个僵尸进程
#include <sys/types.h>
#include <unistd.h> /* create a ZOMBIE * ps -ax | grep a.out to show the zombie */
int main()
{ if(fork()) { // 父进程while(1){ sleep(1); }} // 子进程
}
子进程啥事不干,退出,父进程循环不调用wai回收子进程
表示为僵尸进程
孤儿进程
如 果 父 进 程 退 出 , 并 且 没 有 调 用 wait 函数 , 它 的 子 进 程 就 变 成 孤 儿 进程 , 会 被 一个 特 殊 进 程 继 承 , 这 就 是 init 进程, init 进程 会 自 动 清理 所 有 它 继 承 的 僵 尸 进 程 。
16.04做了修改由upstart继承
ubuntu14 由init继承】
#include <sys/types.h>
#include <unistd.h> int main()
{ if(fork()) { // 父进程}else{ // 子进程while(1){ sleep(1); }}
}
vfork函数
由于fork完整地拷贝了父进程的整个地址空间,因此执行速度是比较慢的。
为了提高效率, Unix系统设计者创建了vfork。
vfork也创建新进程,但不产生父进程的副本。
它通过允许父子进程可访问相同物理内存从而伪装了对进程地址空间的真实拷贝,当子进程需要改变内存中数据时才拷贝父进程。
这就是著名的“写操作时拷贝” (copy-on-write)技术
vfork与fork区别
关键区别一: vfork 直接使用父进程存储空间,不用拷贝 关键区别二:vfork 保证子进程先运行,当子进程调用 exit 退出后,父进程才执行
我们要创建一个进程,谁来负责fork?
shell
我们在shell下执行的程序,进程又是如何创建装载的?
函数族
strace
exec函数族
exec函数族提供了一种在进程中启动另一个程序执行的方法。
它可以根据指定的文件名或目录名找到可执行文件, 并用它来取代原调用进程的数据段、 代码段和堆栈段。
在执行完之后, 原调用进程的内容除了进程号外, 其他全部都被替换了。
可执行文件既可以是二进制文件, 也可以是任何Linux下可执行的脚本文件。
exec函数族-何时使用?
当进程认为自己不能再为系统和用户做出任何贡献了时就可以调用exec函数,让自己执行新的程序
如果某个进程想同时执行另一个程序,它就可以调用fork函数创建子进程,然后在子进程中调用任何一个exec函数。这样看起来就好像通过执行应用程序而产生了一个新进程一样
exec函数族语法
#include <unistd.h>int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
函数返回值 :-1:出错
exec函数族使用区别
可执行文件查找方式
表中的前四个函数的查找方式都是指定完整的文件目录路径,
而最后两个函数(以p结尾的函数)可以只给出文件名, 系统会自动从环境变量“$PATH” 所包含的路径中进行查找。
参数表传递方式
两种方式:
逐个列举或是将所有参数通过指针数组传递
以函数名的第五位字母来区分,
字母为“l”(list)的表示逐个列举的方式;• 字母为“v”(vertor)的表示将所有参数构造成指针数组传递,其语法为char *const argv[]
环境变量的使用
exec函数族可以默认使用系统的环境变量,也可以传入指定的环境变量。
这里,以“e”(Enviromen)结尾的两个函数execle、 execve就可以在envp[]中传递当前进程所使用的环境变量
eg
p
而最后两个函数(以p结尾的函数)可以只给出文件名, 系统会自动从环境变量“$PATH” 所包含的路径中进行查找。
l
字母为“l”(list) 表示参数逐个列举的方式;
v
字母为“v”(vertor)的表示将所有参数构造成指针数组传递,其语法为char *const argv[]
echo $PATH
#include <stdio.h>
#include <unistd.h>int main()
{if (execlp("ps", "ps", "-ef", NULL) < 0){ perror("execlp error!");} return 0;
}
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>int main(int argc,char **argv)
{pid_t pid;printf("PID = %d\n",getpid());pid=fork();if(pid==0){ //子进程execvp("ls",argv); // ./r -ef
// execv("/bin/ls",argv); ./run -l
// execl("/bin/ls","ls","-l","/",NULL);//指令路径 指令 参数 目录 空
// execlp("ls","ls","-al","/",NULL);sleep(10);}else if(pid!=-1){ //父进程 printf("\nParrent porcess,PID = %d\n",getpid());}else{ printf("error fork() child proess!");} return 0 ;
}
exit和_exit
_exit和exit的区别
_exit() :
直接使进程终止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;
exit()
在这些基础上作了一些包装,在执行退出之前加了若干道工序。 exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是图中的"清理I/O缓冲"一项。
int main(){printf("Using exit...\n");printf("This is the end");exit(0);
}
#include <stdio.h>
#include <inistd.h>int main(){printf("Using _exit...\n");printf("This is the end");_exit(0);
}
wait和waitpid
wait和waitpid
wait函数
调用该函数使进程阻塞,直到任一个子进程结束或者是该进程接收到了一个信号为止。如果该进程没有子进程或者其子进程已经结束, wait函数会立即返回。
waitpid函数
功能和wait函数类似。可以指定等待某个子进程结束以及等待的方式(阻塞或非阻塞)
waitpid.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>/* wait method: *//* waitpid*/
int main(int argc, char **argv)
{pid_t pid;printf("parent[pid=%d] is born\n", getpid());if (-1 == (pid = fork())) {perror("fork error");return -1;}if (pid == 0){//子进程printf("child[pid=%d] is born\n", getpid());sleep(5);printf("child is over\n");}else{ //parent 父进程pid_t pid_w;while((pid_w = waitpid(pid, NULL, WNOHANG)) == 0) {printf("parent wait w/o HAND and returns with 0\n");sleep(1);}printf("waitpid returns with pid = %d.\n", pid_w);printf("father is over\n");}return 0;
}
wait_z.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>/* no wait and let zombie be */int main(int argc, char **argv)
{pid_t pid;printf("parent[pid=%d] is born\n", getpid());if (-1 == (pid = fork())) {perror("fork error");return -1;}if (pid == 0){printf("child[pid=%d] is born\n", getpid());sleep(10);printf("child is over\n");}else{while(1){};}return 0;
}
wait.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>/* wait */int main(int argc, char **argv)
{pid_t pid;int status;printf("parent[pid=%d] is born\n", getpid());if (-1 == (pid = fork())) {perror("fork error");return -1;}if (pid == 0){printf("child[pid=%d] is born\n", getpid());sleep(10);printf("child is over\n");exit(7);return 123;}else{pid_t pid_w;pid_w = wait(&status);//等待子进程退出 0x7b00if (pid_w < 0) {perror("wait error");return 1;}printf("status=%x \n",status);if (WIFEXITED(status)) {//正常退出status = WEXITSTATUS(status);//提取返回信息printf("wait returns with pid = %d. return status is %d\n", pid_w, status);} else {//非正常退出printf("wait returns with pid = %d. the child is terminated abnormally\n", pid_w);} printf("father is over\n"); return 0;}
}
相关文章:

进程系统调用
进程系统调用 文章目录进程系统调用fork()进程创建:fock()fork函数fork用法僵尸进程孤儿进程vfork函数vfork与fork区别exec函数族exec函数族-何时使用?exec函数族语法exec函数族使用区别exit和_exit_exit和exit的区别wait和waitpidfork() 进程创建&…...

dubbo进阶——服务导出
服务导出 在这里记录一下对" Dubbo 导出服务的过程"的研究。 触发时机 public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEv…...

【竞品分析】如何撰写竞品分析?竞品分析的基本结构?以及优秀的竞品分析案例
文章目录一、撰写竞品分析的意义二、撰写的节点三、竞品分析内容的基本结构四、总结本文对视频 如何撰写竞品分析(demo)进行了总结。一、撰写竞品分析的意义 竞品分析是指对现有的或潜在的竞争产品的优势和劣势进行评价。现在被广泛应用于互联网产品的…...

海思ubootsd卡协议
在start_armboot()函数中调用mmc_initialize(0)初始化mmc;最终调用到int hi_mci_initialize(unsigned int dev_num)函数;内容如下:static int hi_mci_initialize(unsigned int dev_num) {struct mmc *mmc NULL;static struct himci_host *host;unsigned int regval;unsigned l…...

nuxt3使用总结
目录 背景 安装 项目配置 路由 Tailwindcss引入 全局样式配置 css预处理器 安装 Tailwindcss 项目的配置 部署上线 seo优化 背景 新入职了一家公司,刚进入公司第一个需求就是先做一个公司的官网,需要使用vue写,作为祖师爷的粉丝…...

指向函数的指针详解,以及如何使用指向函数的指针变量做函数参数
指向函数的指针作为函数参数,是 C 语言实际应用中的一个比较深入的部分。 目录 一、什么是函数的指针 二、用函数指着变量调用函数 2.1举例说明 三、怎样定义和使用指向函数的指针变量 3.1定义指向函数的指针变量 3.2指向函数的指针变量详解 3.3通过指针变量…...

Spring——spring整合JUnit
JUnit定义: Junit测试是程序员测试,即所谓 白盒测试 ,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。 Junit是一套框架,继承TestCase类,就可以用Junit进行…...

保障信息安全:使用PyZbar库识别二维码图片可以快速获取二维码中的信息,保障信息安全。
目录 简介: 源代码: 源代码说明: 效果如下所示: 简介: 不用摄像头识别二维码可以应用在以下场景: 批量处理二维码图片:可以在服务器上使用PyZbar等库来批量处理二维码图片,例如读…...

从LeNet到ResNet:深入探索卷积神经网络
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...

计算机组成原理_总线标准
计算机组成原理总目录总线标准 总线标准是系统与各模块、模块与模块之间的一个互连的标准,就像我们用汉语来相互交流一样。 1. 系统总线 ISA总线的扩展插槽,其颜色一般为黑色,比PCI接口插槽要长些,位于主板的最下端。 可插接显卡&…...

蓝桥杯C/C++VIP试题每日一练之芯片测试
💛作者主页:静Yu 🧡简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者 💛社区地址:前端知识交流社区 🧡博主的个人博客:静Yu的个人博客 🧡博主的个人笔记本:前端面试题 个人笔记本只记录前端领域的面试题目,项目总结,面试技…...

树莓派测试wifi与eth速率
测试网速方法: 1.安装插件: 首先在树莓派端安装iperf3 sudo apt install iperf3PC端也需要安装iperf3,单击下面网址即可 下载网址 压缩包解压到桌面,文件内容如下图所示: 2.开始测速服务: 树莓派端在…...

关系抽取方面的基础
关系抽取方面的基础一、基本概念1. 什么是关系抽取(Relation Extraction,RE)?2. 都有什么奇怪的关系?3. 任务评价指标二、 关系抽取方法2.1 按模型结构分——Pipeline 和 Joint方法Pipeline方法Joint方法2.2 按解码方式…...

蓝桥杯嵌入式(G4系列):定时器捕获
前言: 定时器的三大功能还剩下最后一个捕获,而这在蓝桥杯嵌入式开发板上也有555定时器可以作为信号发生器供定时器来测量。 原理图部分: 开发板上集成了两个555定时器,一个通过跳线帽跟PA15相连,最终接到了旋钮R40上&…...

多态的定义、重写、原理
多态 文章目录多态多态的定义和条件协变(父类和子类的返回值类型不同)函数隐藏和虚函数重写的比较析构函数的重写关键字final和override抽象类多态的原理单继承和多继承的虚函数表单继承下的虚函数表多继承下的虚函数表多态的定义和条件 定义࿱…...
Angular 配置api代理 proxy 实践
话不多说,直奔主题 $方式一 第一步,在根目录或/src 下新建一个 proxy.conf.json 文件 备注:这里不用纠结文件名称即xxx.xxx.json,只要使用时能找到,且正确配置文件内容格式即可 {"/dev-list": {"target…...
ES: 数据增,删,改,批量操作
1> 指定id 新增 _id 1 新增一条. 此命令重复执行,就是更新id1的数据 POST employee_zcy/_doc/1 {"uid" : "1234","phone":"12345678909","message" : "qq","msgcode" : "1","send…...
伯努利方程示例 Python 计算(汽水流体和喷泉工程)
伯努利原理 在流体的水平流动中,流体速度较高的点比流体速度较慢的点具有更小的压力。 不可压缩流体在到达狭窄的收缩部分时必须加速,以保持恒定的体积流量。 这就是为什么软管上的窄喷嘴会导致水流加速的原因。 但有些事情可能会困扰您这一现象。 如果…...
2022年中职网络安全竞赛——应用服务漏洞扫描与利用解析(详细)
应用服务漏洞扫描与利用 任务环境说明: 服务器场景:Server2115服务器场景操作系统:未知(关闭链接)使用命令nmap探测目标靶机的服务版本信息,将需要使用的参数作为FLAG进行提交;通过上述端口访问靶机系统并探测隐藏的页面,将找到的敏感文件、目录名作为FLAG(形式:[敏…...

yyds,Elasticsearch Template自动化管理新索引创建
文章目录一、什么是Elasticsearch Template?二、Elasticsearch Template的用法2.1、创建模板2.2、验证模板2.3、应用模板2.4、删除模板2.5、组合模板2.6、如何在同一个模板中定义多种匹配模式2.7、模板优先级2.8、提前模拟索引的最终映射三、Elasticsearch Template…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
Git 命令全流程总结
以下是从初始化到版本控制、查看记录、撤回操作的 Git 命令全流程总结,按操作场景分类整理: 一、初始化与基础操作 操作命令初始化仓库git init添加所有文件到暂存区git add .提交到本地仓库git commit -m "提交描述"首次提交需配置身份git c…...

RKNN开发环境搭建2-RKNN Model Zoo 环境搭建
目录 1.简介2.环境搭建2.1 启动 docker 环境2.2 安装依赖工具2.3 下载 RKNN Model Zoo2.4 RKNN模型转化2.5编译C++1.简介 RKNN Model Zoo基于 RKNPU SDK 工具链开发, 提供了目前主流算法的部署例程. 例程包含导出RKNN模型, 使用 Python API, CAPI 推理 RKNN 模型的流程. 本…...

简单聊下阿里云DNS劫持事件
阿里云域名被DNS劫持事件 事件总结 根据ICANN规则,域名注册商(Verisign)认定aliyuncs.com域名下的部分网站被用于非法活动(如传播恶意软件);顶级域名DNS服务器将aliyuncs.com域名的DNS记录统一解析到shado…...

Centos 7 服务器部署多网站
一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站,目录结构如下: bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…...