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

_Linux进程控制

文章目录

  • 学习进程创建
    • 1. fork函数初识
    • 2. 进程=内核数据结构+进程代码和数据!
    • 3. 数据分离
    • 4. fork常规用法
    • 5. fork调用失败的原因
  • 学习到进程终止,认识 $?
  • 进程终止
    • 1. 进程退出场景
    • 2. 进程常见退出方法
    • 3. 正常终止(可以通过 echo $? 查看进程退出码):
      • _exit函数与exit函数
    • 4. return退出
  • 进程等待
    • 1. 进程等待必要性
    • 2. 进程等待的方法
      • wait方法
      • waitpid方法

学习进程创建

1. fork函数初识

 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1

fork函数返回值:
	子进程返回0,
	父进程返回的是子进程的pid

例子:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
  int ret = fork();
  if(ret < 0)
  {
	perror("fork");
	return 1;
  }
  else if(ret == 0)  //child
  { 
	printf("I am child : %d!, ret: %d\n", getpid(), ret);
  }
  else  //father
  { 
	printf("I am father : %d!, ret: %d\n", getpid(), ret);
  }
  sleep(1);
  return 0;
}

在这里插入图片描述

  • 进程调用fork,当控制转移到内核中的fork代码后,内核做:
    • 分配新的内存块和内核数据结构给子进程。
    • 将父进程部分数据结构内容拷贝至子进程。
    • 添加子进程到系统进程列表当中。
    • fork返回,开始调度器调度。

2. 进程=内核数据结构+进程代码和数据!

我们知道进程=内核数据结构+进程代码和数据!

内核数据结构:操作系统管理的(OS)
进程代码和数据:一般来自磁盘中,也就是你的c/c++程序加载到物理内存中的结果。

注意:

  • 代码:都是不可被写的,只能读取。
  • 数据:可能被修改的,所以必须分离 。

3. 数据分离

OS采用写时拷贝技术

  • 写时拷贝:
    • 通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。具体见下图:
      • 在这里插入图片描述
int main()
{
  const char* str="aaa";
  const char* str1="aaa";

  printf("%p---------%p\n", str, str1);
  return 0;
}

在这里插入图片描述

如上我们知道编译器编译程序的时候,尚且知道节省空间。

OS选择写时拷贝的技术,对父子进程进行分离原因:
1.用的时候给你分配。是一种高效的使用内存的表现。
2.OS无法在代码执行前预知哪些空间会被访问。

当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以
开始它们自己的旅程,看如下程序:

int main()
{
    printf("Before: pid is %d\n", getpid());
    int ret = fork();

    if(ret < 0)
    {
      perror("fork");
      return 1;
    }
    printf("after: pid is %d\n", getpid());
    
    sleep(1);
    return 0;
}

运行结果:
在这里插入图片描述

这里看到了三行输出,一行before,两行after。进程3834先打印before消息,然后它有打印after。另一个after消息有3835打印的。注意到进程3835没有打印before,为什么呢?如下图所示:

在这里插入图片描述
所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。

虽然父子进程各自调度,各自会修改EIP,但是已经不重要了,因为子进程已经认为自己EIP起始值就是fork之后的代码。

4. fork常规用法

  • 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
  • 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

5. fork调用失败的原因

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

学习到进程终止,认识 $?

进程终止

1. 进程退出场景

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

2. 进程常见退出方法

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

    1. 从main返回
    1. 调用exit
    1. _exit
      在这里插入图片描述
      这里的退出码 0表示成功退出, 非零表示异常退出。

_exit函数与exit函数

#include <unistd.h>
void exit(int status);
void _exit(int status);
参数:status 定义了进程的终止状态,父进程通过wait来获取该值

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

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

例子:

int main()
{
	printf("1234");
	_exit(0);
}

运行结果:

[Ding@VM-4-6-centos 22915]$ ./myproc
[Ding@VM-4-6-centos 22915]$

int main()
{
	printf("1234");
	exit(0);
}

运行结果:

[Ding@VM-4-6-centos 22915]$ ./myproc
1234[Ding@VM-4-6-centos 22915]$

4. return退出

return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做 exit的参数。

进程等待

1. 进程等待必要性

  • 之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。
  • 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
  • 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
  • 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。

2. 进程等待的方法

wait方法

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:

成功返回被等待进程pid,失败返回-1。

参数:

输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

waitpid方法

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:

当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

参数:
pid:

Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。

status:

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

options:

WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

获取子进程status

  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
    否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位)
    在这里插入图片描述

测试代码:

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(void)
{
	pid_t pid;
	if ((pid = fork()) == -1)
		perror("fork"), exit(1);
	if (pid == 0) {
		sleep(20);
		exit(10);
	}
	else {
		int st;
		int ret = wait(&st);
		if (ret > 0 && (st & 0X7F) == 0) { // 正常退出
			printf("child exit code:%d\n", (st >> 8) & 0XFF);
		}
		else if (ret > 0) { // 异常退出
			printf("sig code : %d\n", st & 0X7F);
		}
	}
}

运行结果:
[Ding@VM-4-6-centos 22915]$ ./myproc #等20秒退出
child exit code:10
[Ding@VM-4-6-centos 22915]$ ./myproc #在其他终端kill掉
child exit code:9

.
.
.
感觉有所收获的话,友友们给小丁一个赞👍

相关文章:

  • vue3.0--1.vue3.0环境集成、setup、ref函数、reactive函数、计算属性(computed)
  • 基于Opencv5.x(C++)流媒体视频流实现网页浏览器人脸检测
  • 网络安全——XSS跨站脚本攻击
  • AT24C02存储与读取数据
  • Linux高级编程--gdb调试
  • 家校协同小程序实战教程
  • 沉睡者C - 想要通过网上来赚钱,悟性很重要
  • Java集合面试小结(2)
  • 【uiautomation】微信群发消息,可发送文本 文件
  • 【network】windows 获取Adapter 名称
  • Python 基础学习
  • 网课搜题接口公众号搭建详细步骤
  • 继承的使用以及super关键字和重写以及Object类
  • Spring中的AOP翻转的使用与在事务管理中的表现
  • DataOps: A New Discipline 数据治理的下一步
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 78. Subsets
  • CSS中外联样式表代表的含义
  • C学习-枚举(九)
  • github指令
  • Intervention/image 图片处理扩展包的安装和使用
  • JavaScript 奇技淫巧
  • js递归,无限分级树形折叠菜单
  • LeetCode18.四数之和 JavaScript
  • log4j2输出到kafka
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • web标准化(下)
  • 给github项目添加CI badge
  • 记一次用 NodeJs 实现模拟登录的思路
  • 京东美团研发面经
  • 力扣(LeetCode)21
  • 全栈开发——Linux
  • 手写一个CommonJS打包工具(一)
  • 数组大概知多少
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • Hibernate主键生成策略及选择
  • ​linux启动进程的方式
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​低代码平台的核心价值与优势
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (汇总)os模块以及shutil模块对文件的操作
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转) RFS+AutoItLibrary测试web对话框
  • .gitignore文件---让git自动忽略指定文件
  • .NET : 在VS2008中计算代码度量值
  • .NET 8.0 发布到 IIS
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET 反射 Reflect
  • .net 验证控件和javaScript的冲突问题
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验