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

OS进程控制

进程创建

fork()

关于进程的创建主要是使用fork创建子进程,前面链接有讲如何fork创建子进程,这里不在多讲。

https://blog.csdn.net/2301_80820096/article/details/147480284?spm=1001.2014.3001.5501

os底层如何创建

1.使用fork创建子进程后,os会给子进程分配内存数据结构(pcb)。

2.os将父进程的部分数据结构(mm_struct,页表等)拷贝给子进程。

3.添加子进程到系统进程的列表中(就绪)。

4.fork返回开始被调度(调度)。

fork之前父进程独立执行,fork之后,父子各自执行流执行。创建出的子进程会执行父进程之后的代码。

写时拷贝

在创建子进程后,对于父进程的一些代码数据是共享的,但当任意一方试图写入时,便以写时拷贝的方式各自生成一份副本,展示了进程独立性。

原本的代码段时可写的,但当创建子进程之后就变为只读了,当任意一方想要修改,os会报错,然后生成副本供一方使用。(也可以说写时拷贝是基于系统报错完成的)。

写时拷贝的优点

1.减少进程创建的时间。

2.减少内存浪费(父进程每个数据子进程不一定都要更高,内存不一定都要申请)。

fork常规用法

1.父进程创建出子进程,让子进程执行其他的代码和数据。

2.一个进程执行不同程序,eg:子进程返回后调用exec函数。

for调用失败的原因

1.系统中有太多进程,内存严重不足

2.实际用户的进程超过限制。

进程终止 

定义:

进程终止的本质就是释放系统资源,释放相关的内核数据结构(pcb)和代码数据。。

进程退出场景 

1.代码运行完毕,返回结果正确(return 0)。

2.代码运行完毕,返回结果错误 (return !0)。  

3.代码异常终止,(退出码无意义   )。

查看最近进程退出码:echo $?

查看具体的退出码详细信息:sreerror(i);

return errno:直接返回出错 的退出码

exit(c)VS _exit(系统)

exit:语言层面的库函数(exit底层调用_exit),会自动刷新缓冲区。

_exit():系统层面的接口,不会刷新缓冲区。

(可通过打印printf("/")加不加反斜杠看出)

引出:系统层面不会刷新缓冲区证明缓冲区不在系统内部,可能存在库函数和系统调用中间这个地方。   

进程等待

为什么要进行进程等待(必要性)

1.父进程等待回收子进程,以免造成"僵尸进程",造成内存泄漏。

2.父进程创建子进程就是想让子进程完成某些任务,完成任务怎么样,要把结果返回给父进程。

总结一句话:父进程通过进程等待的方式,回收子进程资源获取子进程退出信息

如何进行进程等待

wait()

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int* status);
返回值:
成功返回被等待进程pid,失败返回-1
参数:
输出型参数,获取子进程退出状态,不想关心设置成为NULL
//父进程调用wait()时,子进程没有退出时,父进程处于阻塞状态。 

案列验证:

#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;
//验证回收僵尸进程
int main(){pid_t pid=fork();if(pid==0){int cnt=5;while(cnt>0){printf("我是子进程,pid=%d,ppid=%d\n",getpid(),getppid());cnt--;sleep(1);}exit(0);}//父进程回收sleep(10);///可以屏蔽和放开以下代码来验证wait回收了子进程,解决了僵尸进程问题pid_t rid=wait(NULL);if(rid>0){cout<<"wait sucess!!!"<<endl;}sleep(10);return 0;
}
//另开终端执行ps -ajx | grep 子进程pid

waitpid()

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收等待的子进程的进程PID
//如果设置了选项WNOHANG,⽽调⽤中waitpid发现没有已退出的⼦进程可收集,则返回0
//如果调⽤中出错,则返回-1,这时errno会被设置成相应的值以指⽰错误所在;   
参数:
pid
Pid=-1,等待任⼀个⼦进程。与wait等效。
Pid>0.等待其进程IDpid相等的子进程。
status: 输出型参数
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是
否是正常退出)
WEXITSTATUS(status): WIFEXITED⾮零,提取⼦进程退出码。(查看进程的
退出码)
options:默认为0,表示阻塞等待(等同wait)//等待子进程结束
WNOHANG: 非阻塞调用。指定的pid子进程没有结束,则waitpid()函数返回0,不予以 等
待。若正常结束,则返回该⼦进程的ID

理解status输出型参数

status是wait/waitpid函数中的一个输出型参数,目的是输出子进程的退出信息(主要整数标示)。

int status=0;

&status:拿到子进程退出信息

由下图我们进程正常退出可以看到我们使用echo $?拿到退出进程的退出码就是根据这个原理(status>>8)&0xff:退出码

(status&0x7f):异常终止信号

进程异常被终止:下边的终止信号低7位保存异常退出信号。(core dump标志位解释后边加进来)

对于整形int表示32个比特位,其中高16位不用来表示,第16位的前八位用来描述退出码。

。 

如果进程不异常,正常退出,那么低7位为0

如果进程异常退出,那么低7位就不可能为0,这时就不用关系次低8为的退出码了(无意义)。

退出状态和退出码怎么被父进程拿到

解释:子进程退出后把自己的退出状态保存至自己的task_struct(pcb)中,父进程通过系统调用(wait/waitpid)的方法来获得子进程退出信息。

参数option

非阻塞轮询&阻塞等待

非阻塞轮询:用户向os多次发起请求,但遭到拒绝,这时用户继续向操做系统发起请求。

阻塞等待(类似scanf):用户向os发起一次请求,没遭拒绝,但os也不给用户返回服务,这时候称为阻塞。

非阻塞轮询的返回值

大于0 等待结束

等于0调用结束,但子没有退出

小于0调用失败

非阻塞等待的优点

在非阻塞调用,请求方和服务方可以并发在进行其他事情(效率较高)。

进程替换(了解即可)

简单理解:程序替换就是通过特定接口(execl*类似接口),加载磁盘上的一个全新的程序(代码和数据)。

程序替换可以替换我们自己写的程序

以一个程序替换python程序举例:

//c++主程序
int main(){printf("myname is c++\n");execl("/usr/bin/python3","python","python.py",NULL);return 0;
}
//python程序
#!/usr/bin/python3
print("hello python!")
//运行结果
//myname is c++
//hello python!
//程序替换成功

程序替换后并不等于新建一个新的程序

验证代码:

解释:主程序pid和调用程序pid一致说明使用execl进程程序替换时并没有新建程序。

//主程序code.cc
int main(){printf("mypid:%d\n",getpid());execl("./code1","code1",NULL);return 0;
}
//调用程序code1.cc
int main(){cout<<"i am new,my pid:"<<getpid()<<endl;return 0;
}
//运行结果
mypid:901764
i am new,my pid:901764

进程替换中的相关exec*函数介绍

1.int execl(const char *path, const char *arg, ...);  //-l 列表的意思

  eg:execl("/usr/bin/ls","-a","-l",NULL);

2.int execlp(const char* file,const char*arg,....);   //-p 环境变量,默认找路径

  eg:execlp("ls","ls","-a","-l")

3.int execv(const char *path, char *const argv[]); // v(vector) 数组存储命令行参数

  eg: const char* argv[ ]={"ls","-l","-a",NULL};

        execv("usr/bin/ls","ls" ,argv);

4.int execvp(const char *file, char *const argv[]);(结合上边,不足举例)

5.int execvpe(const char *file, char *const argv[],const char* env[]);//e 环境变量 要求调用的程序使用全新的环境变量

6.int execve(char* filename,char *constargv[],char *const envp[]); (系统层面)上边五个所有接口底层都是调用这个函数进行的。

http://www.dtcms.com/a/614070.html

相关文章:

  • datax的shell脚本常见报错
  • Java在线编译C语言 | 快速高效的跨语言在线编译工具
  • 前端响应式图片实现,srcset与sizes
  • 品牌网站建设解决期货软件定制开发公司
  • OpenCV(二十五):方盒滤波与均值滤波
  • Vscode 配置C++ Mingw调试、编译环境-无需修改系统PATH变量的VS Code配置方法
  • superset_config.py 配置文件的参数详解
  • 搭建本地deepseek大模型
  • 阳泉 网站建设合作网页设计心得体会2000字
  • 网站程序授权码电商网站经营性备案
  • 自动化测试任务或者定义AI AGENT(智能体)任务,通过使用它可以操作浏览器来执行特定操作,如访问网页、单击按钮、提取网页信息等。 ...
  • BFS 广度优先搜索算法
  • Jinja 模板引擎介绍文档
  • 深圳响应样式网站建设费用灵台县门户网
  • Excel工作簿自动销毁功能,使用时间到期后自动删除文件
  • Linux-信号2
  • 河南省两学一做网站官网建设的意义
  • 【Python TensorFlow】BiTCN-BiGRU双向时间序列卷积双向门控循环神经网络时序预测算法(附代码)
  • 公司网站策划书广州工商注册流程
  • C语言是一种编译器吗 | 探讨C语言及其编译原理
  • LeetCode热题100--39. 组合总和
  • 网站开发包含网站维护吗网站建设的技术保证怎么写
  • Java事件处理机制
  • 前端构建工具缓存策略,contenthash与chunkhash
  • 企业门户网站制作网站过期查询
  • 信阳网站优化免费的开源网站
  • Redis(125)Redis在社交网络中的应用有哪些?
  • 吴恩达新课程:Agentic AI(笔记10)
  • 随笔之工作方法的“高与低”
  • 栈+贪心