首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【linux学习指南】进程创建与终止

【linux学习指南】进程创建与终止

作者头像
学习起来吧
发布2025-01-01 08:51:36
发布2025-01-01 08:51:36
6000
举报
文章被收录于专栏:学习C/++学习C/++

加粗样式

📝进程创建

🌠 fork函数初识

在linux中fork函数是⾮常重要的函数,它从已存在进程中创建⼀个新进程。新进程为⼦进程,⽽原进程为⽗进程。

代码语言:javascript
复制
 #include <unistd.h>
 pid_t fork(void);
返回值:⾃进程中返回0,⽗进程返回⼦进程id,出错返回-1

进程调⽤fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给⼦进程
  • 将⽗进程部分数据结构内容拷⻉⾄⼦进程
  • 添加⼦进程到系统进程列表当中
  • fork返回,开始调度器调度

当⼀个进程调⽤fork之后,就有两个⼆进制代码相同的进程。⽽且它们都运⾏到相同的地⽅。但每个进程都将可以开始它们⾃⼰的旅程,看如下程序。

这⾥看到了三⾏输出,⼀⾏before,两⾏after。进程43676先打印before消息,然后它有打印after。 另⼀个after消息有1398691打印的。注意到进程1398691没有打印before,为什么呢?如下图所⽰

所以,fork之前⽗进程独⽴执⾏,fork之后,⽗⼦两个执⾏流分别执⾏。注意,fork之后,谁先执⾏完 全由调度器决定。

🌉fork函数返回值

  • ⼦进程返回0
  • ⽗进程返回的是⼦进程的pid。

🌠 写时拷⻉

通常,⽗⼦代码共享,⽗⼦再不写⼊时,数据也是共享的,当任意⼀⽅试图写⼊,便以写时拷⻉的⽅式各⾃⼀份副本。具体⻅下图:

因为有写时拷⻉技术的存在,所以⽗⼦进程得以彻底分离离!完成了进程独⽴性的技术保证!

写时拷⻉,是⼀种延时申请技术,可以提⾼整机内存的使⽤率

🌉fork常规⽤法

  • ⼀个⽗进程希望复制⾃⼰,使⽗⼦进程同时执⾏不同的代码段。例如,⽗进程等待客⼾端请求,⽣成⼦进程来处理请求。
  • ⼀个进程要执⾏⼀个不同的程序。例如⼦进程从fork返回后,调⽤exec函数。

🌉fork调⽤失败的原因

  • 系统中有太多的进程
  • 实际⽤⼾的进程数超过了限制

🌠进程终⽌

进程终⽌的本质是释放系统资源,就是释放进程申请的相关内核数据结构和对应的数据和代码。

🌉进程退出场景

  1. 代码运⾏完毕,结果正确
  2. 代码运⾏完毕,结果不正确
  3. 代码异常终⽌

🌉进程常⻅退出⽅法

正常终⽌(可以通过 echo $? 查看进程退出码):

  1. 从main返回
  2. 调⽤exit
  3. _exit

异常退出:

  • ctrl+c 信号终⽌

🌉退出码

退出码(退出状态)可以告诉我们最后一次执行的命令的状态。在命令结束以后,我们可以知道命令是成功完成的还是以错误结束的。其基本思想是,程序返回退出代码0时表示执行成功,没有问题。

代码10以外的任何代码都被视为不成功。

Linux Shell 中的主要退出码 :

退出码

解释

0

命令成功执行

1

通用错误代码

2

命令(或参数)使用不当

126

权限被拒绝(或)无法执行

127

未找到命令,或PATH错误

128 + n

命令被信号从外部终止,或遇到致命错误

130

通过Ctrl + C或SIGINT终止(终止代码2或键盘中断)

143

通过SIGTERM终止(默认终止)

255/ *

退出码超过了0 - 255的范围,因此重新计算(LC3TT注:超过255后,用退出码取模)

  • 退出码0表示命令执行无误,这是完成命令的理想状态。
  • 退出码1我们也可以将其解释为“不被允许的操作”。例如在没有sudo权限的情况下使用yum;再例如除以0等操作也会返回错误码1,对应的命令为let a=1/ 0
  • 130 (SIGINT]或^c))和143([SIGTERM))等终止信号是非常典型的,它们属于128+n信号,其中n代表终止码。
  • 可以使用strerror函数来获取退出码对应的描述。

🌉_exit函数

代码语言:javascript
复制
#include <unistd.h>
 void _exit(int status);
参数:status 定义了进程的终⽌状态,⽗进程通过wait来获取该值

说明:虽然status是int,但是仅有低8位可以被⽗进程所⽤。所以_exit(-1)时,在终端执⾏$?发现返回值是255。

🌉exit函数

代码语言:javascript
复制
 #include <unistd.h>
 void exit(int status);

exit最后也会调⽤_exit,但在调⽤_exit之前,还做了其他⼯作:

  1. 执⾏⽤⼾通过atexit或on_exit定义的清理函数。
  2. 关闭所有打开的流,所有的缓存数据均被写⼊
  3. 调⽤_exit

实例:

代码语言:javascript
复制
int main()
{
    printf("hello");
    exit(0);
}
运⾏结果: [root @localhost linux] #./a.out
hello[root @localhost linux]#

int main()
{
    printf("hello");
    _exit(0);
}
运⾏结果: 
[root @localhost linux] #./a.out
[root @localhost linux] #

🌉return退出

return是⼀种更常⻅的退出进程⽅法。执⾏returnn等同于执⾏exit(n),因为调⽤main的运⾏时函数会将main的返回值当做exit的参数。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 📝进程创建
  • 🌠 fork函数初识
    • 🌉fork函数返回值
  • 🌠 写时拷⻉
    • 🌉fork常规⽤法
    • 🌉fork调⽤失败的原因
  • 🌠进程终⽌
    • 🌉进程退出场景
    • 🌉进程常⻅退出⽅法
    • 🌉退出码
    • 🌉_exit函数
    • 🌉exit函数
    • 🌉return退出
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档