当前位置: 首页 > news >正文

[ linux-系统 ] 进程控制

进程创建fork

fork 之后发生了什么

  1. 将给子进程分配新的内存块和内核数据结构(形成了新的页表映射)
  2. 将父进程部分数据结构内容拷贝至子进程
  3. 添加子进程到系统进程列表当中
  4. fork 返回,开始调度器调度

 父进程创建子进程,代码是共享的,数据不修改时也是共享的,子进程数据修改时发生写时拷贝

写时拷贝

父进程创建子进程之前,先把数据权限改为只读的,子进程将数据修改时,触发系统错误,触发缺页中断,系统检测,系统检测如果代码段发生错误,就杀掉进程,如果是数据段发生错误,系统就判定要发生写时拷贝,系统申请内存,发生拷贝,修改页表,恢复执行,恢复权限为只读

进程终止

错误码

为什么要使用return ? 

return返回的数字表示是否错误 : 0表示成功,非0表示错误

进程中,父进程会关心我的运行情况

main函数的返回值本质:表示进程运行完成时,是否是正确的结果,如果不是,我们可以用不同的数字表示出错的原因

系统给我们提供了一批错误码

C 语言当中有个的 string.h 中有一个 strerror 接口 以及 errno.h 中有一个errno接口

写linux中以下代码可以将所有错误码信息打印出来,一共有133条错误码 

总结:

main函数结束表示进程退出,main函数的返回值表示进程的退出码

进程的退出码可以由系统默认提供,也可以自定义约定

进程终止的方式

1.main函数return  (只有main函数return表示进程结束,其他函数结束表示当前函数返回)

2.exit (在代码的任何地方,表示进程结束)

3._exit

exit和_exit

exit会刷新缓冲区,_exit不会刷新缓冲区

缓冲区 -- 叫做语言级缓冲区 -- 在C/C++内部,不在操作系统中

exit在man 3 手册,属于库函数 , _exit在man 2 手册,属于系统调用

exit和_exit属于上下层关系,exit就是调用的_exit并封装

进程等待

父进程创建子进程,看以下代码以及运行结果和监视窗口

父进程创建子进程后,如果不管他,子进程运行结束就会变成僵尸进程

所以,父进程创建了子进程,父进程就要等待子进程,直到子进程结束。等待的时候,子进程如果不退,父进程就要阻塞在wait函数内部,wait函数等待任意一个子进程

使用一下wait函数,发现子进程结束后,直接被父进程回收了,监视窗口中也看不到子进程变成僵尸进程了,直接被回收 

waitpid

pid > 0 指定一个子进程  ,  pid == -1 任意子进程

*status 帮助父进程获取子进程的退出信息 (输出型参数)

status不能简单的当作整形来看待,可以当作位图来看待,只研究status低16位比特位

根据以上代码,父进程可以拿到子进程的退出信息

可不可以使用全局变量来获得子进程的退出码?不可以,只能通过系统调用来获取退出信息

重谈进程退出:

1.代码跑完,结果对,return0

2.代码跑完,结果不对,return非0

3.进程异常  OS提前使用信号终止进程

status最低7位提取子进程的退出信号

 

阻塞/非阻塞等待

options决定是否阻塞,0 :阻塞等待  WNOHANG :非阻塞等待

写以下代码及运行结果

  1 #include<iostream>2 #include<unistd.h>3 #include<cstdlib>4 #include<string>5 #include<string.h>6 #include<errno.h>7 #include<vector>8 #include<sys/types.h>9 #include<sys/wait.h>10 #include<functional>11 #include"task.h"12 13 using task_t = std::function<void()>;14 15 16 // 非阻塞等待17 18 void LoadTask(std::vector<task_t> &tasks)19 {20     tasks.push_back(PrintLog);21     tasks.push_back(Download);22     tasks.push_back(BackUp);23 }24 int main()25 {26     std::vector<task_t> tasks;27     LoadTask(tasks);28 29     pid_t id = fork();30     if(id == 0)  // child31     {32         while(1)33         {34             printf("我是子进程,pid: %d\n",getpid());35             sleep(1);36         }37         exit(0);38     }39 40     // father41     while(1)42     {                                                                                                                                                                                                                                                                                                                                                                                 43         pid_t rid = waitpid(id,nullptr,WNOHANG);44         if(rid > 0)45         {46             printf("等待子进程%d成功\n",rid);47             sleep(1);48             break;49         }50         else if(rid < 0)51         {52             printf("等待子进程失败\n");53             sleep(1);54             break;55         }56         else57         {58             printf("子进程尚未退出\n");59             sleep(1);60 61             //阻塞期间父进程做自己的事情62             for(auto &task : tasks)63             {64                 task();65             }66         }67     }68     return 0;69 }

 

可以看到父进程不等待子进程,子进程在完成任务时,父进程也可以做自己的事情

进程程序替换

程序替换是通过特定的接⼝,加载磁盘上的⼀个全新的程序(代码和数据),加载到调⽤进程的地址空间中,看以下代码,我们的myexec程序就执行了ls命令

execl不仅可以替换系统命令,也可以替换我们的可执行程序

看以下代码:验证了程序替换没有创建新进程

 

返回值:成功时没有返回值,失败返回-1

只要返回,就是失败

 可以理解为execl将可执行程序加载到内存

认识全部接口 

execv的使用方法即运行结果 

execlp使用可以不带路径,为什么可以不带路径?

因为execlp会从环境变量PATH中找到路径(有重复的路径就找到第一个)

 

 execvp 

 

对于环境变量:子进程继承父进程的所有环境变量,如果要传递新的环境变量(自己定义,自己传递)    execvpe可以自己导入新的环境变量

 程序替换不影响命令行参数和环境变量

这六个不是系统调用接口,而是C标准库封装的接口。这六个的区别只有传参方式的差别

 真正意义上的系统调用接口是execve

相关文章:

  • helm使用说明和实例
  • 赞助打赏单页HTML源码(源码下载)
  • 基于算法竞赛的c++编程(24)位运算及其应用
  • python3基础语法梳理(一)
  • 安全领域新突破:可视化让隐患无处遁形
  • Easy Excel
  • c语言(持续更新)
  • 使用DataX同步MySQL数据
  • OSPF域内路由
  • matlab时序预测并绘制预测值和真实值对比曲线
  • 6.9本日总结
  • DPC密度峰值聚类
  • PostgreSQL 与 SQL 基础:为 Fast API 打下数据基础
  • 卷积神经网络设计指南:从理论到实践的经验总结
  • CppCon 2015 学习:STL Algorithms in Action
  • CppCon 2015 学习:Transducers, from Clojure to C++
  • 时间同步技术在电力系统中的应用
  • 【习题】DevEco Studio的使用
  • 驭码 CodeRider 2.0 产品体验:智能研发的革新之旅
  • 用递归算法解锁「子集」问题 —— LeetCode 78题解析
  • 网站开发公司杭州/南京关键词优化软件
  • 建站宝盒成品网站演示/广州seo招聘信息
  • java做网站电话注册/网络推广宣传方式
  • 网站策划编辑如何做/跨境电商培训
  • 广告设计专业好吗/seo是什么味
  • 动态网站 教程/百度学术官网入口网页版