【Linux】进程管理

目录

一、进程创建

二、进程等待

1. 阻塞等待

2. 非阻塞等待

3. status位图

三、进程替换

1. exec* 系列函数

2. 高级语言程序替换


一、进程创建

进程是操作系统进程资源分配的最小单位,每一个进程都有自己独立的PID,以及进程控制块PCB。

父进程通过 fork() 创建子进程,子进程的ppid == 父进程pid,父子进程互不干扰。

创建子进程时,操作系统的工作:

  1. 复制主进程的地址空间,包括代码段、数据段、堆、栈等,通过页表的复制机制完成,即操作系统会将父进程的页表复制一份给子进程,在此之后,父子进程共享同样的内存页,虚拟内存页,并且这些内存页都使用写时拷贝技术进行保护,减小内存开销。
  2. 设置子进程唯一标识符PID,复制父进程的文件描述符表,设置父子进程关系,设置子进程的父进程标识PPID。
  3. 初始化子进程的进程控制块PCB,操作系统为子进程分配一个进程控制块,该控制块用来保护进程的状态、优先级、寄存器状态以及其他进程相关的信息。
  4. 设置子进程的初始状态,操作系统将子进程的初始状态设置为就绪态,以便在适当的时候可以运行。

不同系统中对进程设置有不同的状态,Linux系统的进程状态分为:运行态(R)、僵尸态(Z)、暂停态(T)、睡眠态(S)、深度睡眠状态(D)、死亡态(X)。

# 查看进程状态
root@ubuntu:/var/lib/mysql/d1_mytest# ps ajx | head -1 && ps ajx | grep mysqlPPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND1   1276   1275   1275 ?            -1 Sl     123   0:26 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid2620   2989   2989   2620 pts/5      2989 S+    1000   0:00 mysql -u ljc -p3584   7996   7995   3403 pts/1      7995 S+       0   0:00 grep --color=auto mysql
root@ubuntu:/var/lib/mysql/d1_mytest# 

可以通过 kill 控制进程的执行,kill 命令的本质就是向目标进程发送信号。

  • kill -9   PID : 杀死进程
  • kill -19 PID : 暂停进程
  • kill -29 PID : 继续进程

进程状态带 + 号,代表的是前台进程,否则是后台进程。

前台进程在终端运行,后台进程不受终端控制。

二、进程等待

1. 阻塞等待

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()  {pid_t id = fork();if (id == 0) {int cnt = 5;while (cnt) {printf("子进程:%d, 父进程:%d, cnt = %d\n", getpid(), getppid(), cnt--);sleep(1);}exit(10);}//父进程int status = 0;    // 保存退出码pid_t ret = waitpid(id, &status, 0);    //option为 0 代表阻塞等待if (id > 0) {printf("wait success: %d, sign: %d, exit code: %d\n", ret, (status & 0x7F), (status>>8) & 0xFF);}return 0;
}

2. 非阻塞等待

  • 非阻塞等待:子进程未退出,父进程检测之后立即返回
  • 非阻塞等待的意义:不用占用父进程的所有精力,可以在等待期间执行自己的任务
  • WIFEXITED(status):是否正常退出,若正常退出则返回值非零
  • WEXITSTATUS(status):提取子进程退出码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>#define NUM 10typedef void (*func_t)();   //函数指针func_t handlerTask[NUM];//测试样例
void Task1() {printf("handler task1\n");
}void Task2() {printf("handler task2\n");
}void Task3() {printf("handler task3\n");
}//给父进程装载任务 
void LoadTask() {memset(handlerTask, 0, sizeof(handlerTask));handlerTask[0] = Task1;handlerTask[1] = Task2;handlerTask[2] = Task3;
}int main() {pid_t id = fork();  //返回的本质就是写入, 写入时发生写时拷贝if (id < 0) {printf("folk error\n");return 1;}else if (id == 0) {int cnt = 5;while (cnt) {printf("我是子进程: %d, 父进程: %d, cnt = %d\n", getpid(), getppid(), cnt--);sleep(1);// int* p = NULL;// *p = 100;       //野指针报错, 退出信号为11}exit(10);}LoadTask();int status = 0;     //不是被整体使用的, 有自己的位图结构//非阻塞轮旋方式等待while (1) {pid_t ret = waitpid(id, &status, WNOHANG);  //非阻塞等待: 子进程未退出, 父进程检测之后立即返回if (ret == 0) {//子进程未退出, waitpid等待失败, 仅仅是检测到子进程状态未退出for (int i = 0; handlerTask[i] != NULL; ++i)handlerTask[i]();}//等待子进程退出成功else if (ret > 0) {//是否正常退出if (WIFEXITED(status)) {//正常退出, WIFEXITED()返回值为!0//判断子进程运行结果是否正确printf("exit_code: %d\n", WEXITSTATUS(status));    }else {//异常退出,被信号杀死printf("child process not normal\n");}break;}else {// waitpid调用失败printf("waitpid call failed\n");break;}sleep(1);}return 0;       
}

3. status位图

  • status退出信号是一个32bit位的位图,只有低16个bit位存储退出信息
  • (status & 0x7F) 为终止信号, (status>>8) & 0xFF) 为退出状态
  • 异常退出,被信号杀死
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main() {pid_t id = fork();if (id == 0) {int cnt = 5;while (cnt) {printf("子进程:%d, 父进程:%d, cnt = %d\n", getpid(), getppid(), cnt--);sleep(1);}int a = 10;a /= 0;         //除 0 异常exit(10);}//父进程int status = 0;pid_t ret = waitpid(id, &status, 0);    //option为 0 代表阻塞等待if (id > 0) {printf("wait success: %d, sign: %d, exit code: %d\n", ret, (status & 0x7F), (status>>8) & 0xFF);}return 0;
}

三、进程替换

1. exec* 系列函数

进程替换:将指定进程的代码加载到指定位置,覆盖自己的代码和数据。

加载器的底层接口,可替换任何后端语言的可执行程序:

  • int execl(const char* path, const char* arg, ...),可变参数列表以NULL结尾
  • int execlp(const char* file, const char* arg, ...),可自动在环境变量中寻找路径
  • int execv(const char* path, char* const arg[]),可变参数数组以NULL结尾
  • int execvp(const char* file, char* const arg[])
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>int main() {printf("process is running\n");pid_t id = fork();if (id == 0) {sleep(1);//execl("/usr/bin/ls", "ls", "-a", "-l", "--color=auto", NULL);//execlp("ls", "ls", "-a", "-l", "--color=auto", NULL);char* const arg[] = {"ls", "-a", "-l", "--color=auto", NULL};//execv("/usr/bin/ls", arg);execvp("ls", arg);exit(10);   //若exc*调用成功,则此句代码被替换}int status = 0;pid_t ret = waitpid(id, &status, 0);if (ret > 0) {printf("wait success, sig = %d, exit code = %d\n", (status & 0x7F), (status>>8) & 0xFF);}printf("process is running done\n");return 0;       
}

execve是系统调用,其他都是封装:

  • int execle(const char* path, const char* arg, ... , char* const envp[]),可传环境变量
  • int execve(const char* path, char* const arg[], char* const envp[])
  • int execvpe(const char* file, char* const arg[], char* const envp[])

2. 高级语言程序替换

#include <stdio.h>
#include <stdlib.h>int main() {printf("C语言程序\n");printf("C语言程序\n");printf("PATH: %s\n", getenv("PATH"));printf("PWD: %s\n", getenv("PWD"));printf("MYENV: %s\n", getenv("MYENV"));printf("C语言程序\n");printf("C语言程序\n");exit(15);
}// 创建一个test.c文件并编译 gcc -o test test.c
#!/bin/python
print('python process')
print('python process')
print('python process')
print('python process')
print('python process')# 创建一个py_test.py文件,chmod u+x py_test.py
# 用进程替换这个程序,并打印环境变量
// 进程替换#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>int main() {printf("process is running\n");pid_t id = fork();if (id == 0) {sleep(1);putenv((char*)"MYENV=123456");     //添加自定义环境变量extern char** environ;execle("./test", "test", NULL, environ);exit(10);   //若exc*调用成功,则此句代码被替换}int status = 0;pid_t ret = waitpid(id, &status, 0);if (ret > 0) {printf("wait success, sig = %d, exit code = %d\n", (status & 0x7F), (status>>8) & 0xFF);}execl("./py_test.py", "py_test.py", NULL);printf("process is running done\n");return 0;       
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/284600.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SAP-ABAP】CO01保存时错误DBSQL_DUPLICATE_KEY_ERROR

找到该表的主键OBJNR&#xff0c;事务代码SM56中查看当前缓冲到该key的号码段&#xff0c;事务代码SNRO修改对象名称OBJNR编号范围状态。 事务代码SM13查看数据更新记录

数据可视化-ECharts Html项目实战(5)

在之前的文章中&#xff0c;我们学习了如何设置滚动图例&#xff0c;工具箱设置和插入图片。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢 数据可视化-ECharts…

nodejs社区垃圾分类管理平台的设计与实现python-flask-django-php

近些年来&#xff0c;随着科技的飞速发展&#xff0c;互联网的普及逐渐延伸到各行各业中&#xff0c;给人们生活带来了十分的便利&#xff0c;社区垃圾分类管理平台利用计算机网络实现信息化管理&#xff0c;使整个社区垃圾分类管理的发展和服务水平有显著提升。 语言&#xf…

qt 实现 轮播图效果,且还有 手动 上一页和下一页 已解决

QT中有 轮播图的需求&#xff0c;按照正常html版本 。只需要配置数组就能搞定&#xff0c;但是c qt版本 应该用什么了。 第一想到的是采用定时器。 // 定时器初始化{m_pTime new QTimer(this);m_pTime->start(4 * 1000);//启动定时器并设置播放时间间隔m_pAutoFlag true;/…

vs2019新建Qt工程中双击 .ui 文件无法打开

vs2019 中创建的 Qt 工程&#xff0c;在使用的过程中&#xff0c;经常会有&#xff1a;双击 .ui 文件&#xff0c;闪退的情况&#xff0c;也即 .ui 文件无法打开&#xff01; 针对该问题的详细解决步骤如下&#xff1a; 1、右击该 .ui 文件&#xff0c;选择“打开方式” 2、…

②零基础MySQL数据库-MySQL约束

作用 表在设计的时候加入约束的目的就是为了保证表中的记录完整性和有效性&#xff0c;比如用户表有些列的值&#xff08;手机号&#xff09;不能为空&#xff0c;有些列的值&#xff08;身份证号&#xff09;不能重复 分类 主键约束(primary key) PK 自增长约束(auto_increme…

是德科技keysight DSOX3024T示波器

181/2461/8938产品概述&#xff1a; DSOX3024T 示波器 要特性与技术指标 使用电容触摸屏进行简洁的触控操作&#xff1a; •提高调试效率 •触控设计可以简化文档记录 •使用起来就像您喜欢的智能手机或平板电脑一样简单 使用 MegaZoom IV 技术揭示偶发异常&#xff1a; •超快…

rpc详解rpc框架

文章目录 概述rpc的优点组件工作流程&RPC的底层原理RPC的底层原理 RPC框架rpc框架优点RPC 的实现基础RPC的应用场景RPC使用了哪些关键技术rpc 调用异常一般怎么处理rpc和http的区别为什么RPC要比HTTP更快一些Dubbo和openfeign 区别远程调用RPC框架传输协议传输速度 概述 在…

135. 分发糖果(力扣LeetCode)

文章目录 135. 分发糖果题目描述贪心算法代码如下 总结 135. 分发糖果 题目描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩…

my2sql —— go语言版binlog解析及闪回工具

之前学习过python语言版binlog解析及闪回工具 MySQL闪回工具简介 及 binlog2sql工具用法 最近听同事介绍有了新的go语言版的my2sql。优点是不需要安装一大堆依赖包&#xff0c;直接可以安装使用&#xff0c;并且解析更高效&#xff0c;试用一下。 一、 下载安装 1. 软件下载 …

【原理图PCB专题】Cadence 17.4 配置Capture.ini让CIS数据库界面查看PCB封装

在CIS数据库中,如果进行了正确配置是可以查看原理图符号库与PCB封装库的。如下所示: 看到封装库的意义在于一个原理图封装是可以对应多个PCB封装的,如同一个原理图座子,对应了侧插或是竖插,那在没有PCB封装的时候,我们只能通过去看详细资料来判断。如果有PCB封装显示,只…

设计模式-访问者(Visitor)模式详解和应用

文章目录 前言访问者模式介绍结构包含的角色应用场景代码示例访问者模式的扩展访问者模式优缺点总结 前言 最近在做一个根据数学表达式生成java执行代码的功能&#xff0c;其中用到了访问者模式。使我对访问者模式有了更深入的理解。故写下此篇文章分享出来&#xff0c;不足之…

IPV6协议之RIPNG

目录 前言&#xff1a; 一、RIPNG与RIP的区别 二、如何配置RIPNG 如何解决RIPNG环路问题呢&#xff1f; 控制RIPNG的选路 1、修改RIPNG默认优先级 2.配置接口附加开销值从而干涉RIPNG的选路 RIPNG拓展配置 1.RIPNG的认证 配置RIPNG进程下的IPsec认证&#xff1a; 配…

Spring Cloud Gateway教程

1 微服务网关概述 Spring Cloud Gateway是在 Spring 生态系统之上构建的API网关服务&#xff0c;旨在为微服务架构应用提供一种简单有效的统一的API路由管理方式。 Spring Cloud Gateway主要功能&#xff1a; 反向代理认证鉴权流量控制熔断日志监控 2 Spring Cloud Gateway三…

基于python+vue超市在线销售系统的设计与实现flask-django-php-nodejs

根据此问题&#xff0c;研发一套超市在线销售系统&#xff0c;既能够大大提高信息的检索、变更与维护的工作效率&#xff0c;也能够方便信息系统的管理运用&#xff0c;从而减少信息管理成本&#xff0c;提高效率。 该超市在线销售系统采用B/S架构、并采用python语言以及django…

拌合楼管理系统(八) c#海康威视摄像头车牌识别

前言: c#调用海康威视SDK实现车牌识别 原本以为海康威视sdk的Demo里面没有车牌识别的实例,后来发现自己肤浅了,官方是有提供的,只是车牌识别是通过安防布警的方式实现的.程序主动监听,触发告警后获取到车牌信息. 一、接口调用的流程&#xff1a; 首先初始化sdk -> 开…

CI/CI实战-jenkis结合gitlab 4

实时触发 安装gitlab插件 配置项目触发器 生成令牌并保存 配置gitlab 测试推送 gitlab的实时触发 添加jenkins节点 在jenkins节点上安装docker-ce 新建节点server3 安装git和jdx 在jenkins配置管理中添加节点并配置从节点 关闭master节点的构建任务数

二分查找法总结

目录 1、思路讲解&#xff08;LC704&#xff09;2、代码思路讲解&#xff08;循环不变量&#xff09;&#xff08;1&#xff09; 左闭右闭&#xff08;2&#xff09;左闭右开&#xff08;3&#xff09;总结&#xff1a;左开右闭和左闭右开&#xff08;4&#xff09;复杂度分析 …

老阳分享|temu跨境电商选品师项目能赚钱吗?

近年来&#xff0c;跨境电商行业蓬勃发展&#xff0c;成为众多创业者追逐的热点。其中&#xff0c;老阳分享的temu跨境电商选品师项目备受关注。那么&#xff0c;这个项目真的能赚钱吗?下面&#xff0c;我们就跟随本文去了解一下。 首先&#xff0c;temu作为拼多多旗下的跨境电…

数据结构与算法4-冒泡排序

文章目录 1. 认识冒泡排序2. 图示2.1 图示12.2 图示2 3. 代码 1. 认识冒泡排序 双层for循环&#xff0c;每次选出最大的数“浮”到数组的最后面&#xff1b;时间复杂度O( n 2 n^2 n2)&#xff0c;空间复杂度O(1);重复地遍历待排序的数列&#xff0c;一次比较两个元素&#xff…