linxu学习之进程
文章目录
- 进程
- 程序和进程
- 产生进程
- 销毁进程
- 多进程高并发设计
- 孤儿僵尸守护进程
- 孤儿进程:
- 守护进程(重点)
- 僵尸进程:
进程
程序和进程
操作系统可以运行多个程序,那他是如何运行的?实际上,CPU的执行是很快的,而待运行的程序很多,那么为了让操作系统运行多个程序,CPU会把它的执行时间划分成很多段,比如每一段是0.1秒,那么就可以这样A程序运行0.1秒,然后B程序运行0.1,然后C程序运行0.2秒,因为这个切换很快,所以我们感觉程序是同时运行的。
产生进程
- 创建进程很简单,直接调用fork函数:pid_t fork(void);
创建进程用法举例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(){int pid = 0;// 父子进程不共享局部变量// pid_t fork(void);pid_t fpid = fork(); // fpid表示fork函数返回的值if(fpid < 0){printf("创建子进程失败\n");return fpid;}else if(fpid == 0){// 创建成功后子进程中fpid == 0pid = getpid();printf("子进程,子进程pid = %d\n",getpid());}else if(fpid > 0){// 创建成功后父进程的fpid 为子进程的pidpid = getpid();printf("父进程,父进程pid = %d\n",getpid());printf("父进程,子进程pid = %d\n",getpid());}// 再创建3个子进程用于观察for(int i = 3 ; i > 0 && fpid > 0 ; i--){fpid = fork();}printf("pid = %d\n",pid);while (1);return 0;
}
调用fork函数后,会创建一个子进程,并且父子两个进程都从fork处执行,fork函数有两个返回值,对于父进程会返回子进程的pid,此时pid会大于0,对于子进程来说,pid会等于0。
局部变量:写时复制,读时共享
销毁进程
exit - 终止正在执行的进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main()
{int pid = 0;// pid_t fork(void);pid_t fpid = fork();if (fpid < 0){printf("创建子进程失败\n");return fpid;}else if (fpid == 0){printf("我是子进程,马上就要exit了\n");exit(-1);printf("子进程还活着\n");}else if (fpid > 0){printf("父进程还活着\n");}while (1);return 0;
}
这里子进程已经退出,但是父进程没有执行完毕,导致子进程没有回收变成僵尸进程
多进程高并发设计
优点:
-
若要用多进程实现高并发那么自己linxu系统cpu有多少核,就产生多少个进程多个核可以并发执行只有多个进程在不同的核上运行才可以充分利用多核系统的并发处理能力
-
比如:cpu为四核,那么主进程就产生4个子进程,让四个子进程分别在不同的核上运行,
-
4个子进程在工作的时候,把任务放在一个共享内存中(通过内存映射,使多个进程可以访问一个内存),哪个任务做完了,就接着拿任务给每个子进程的负载均衡
-
职责明确:父进程管理生死,子进程工作
查看cpu核数
cat /proc/cpuinfo
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);int main(int argc, char **argv)
{// 子进程用于工作,父进程用于管理子进程// 开启工作进程,创建4个子进程start_worker_processes(4);// 管理子进程wait(NULL);
}// 开启工作进程
void start_worker_processes(int n)
{int i = 0;for (i = n - 1; i >= 0; i--){// 创建子进程spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");}
}// 创建子进程
// spawn_proc_pt 类型的函数:void worker_process_cycle(void *data)
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{pid_t pid;pid = fork(); // 创建子进程switch (pid){case -1:fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);return -1;case 0:proc(data); // 成功创建子进程后让子进程去工作return 0;default:break;}printf("start %s %ld\n", name, (long int)pid);return pid;
}// 给进程安排工作
void worker_process_cycle(void *data)
{// data 其实是一个int*类型int worker = (intptr_t)data;// 初始化worker_process_init(worker);// 干活for (;;){sleep(10);printf("pid %ld ,doing ...\n", (long int)getpid());}
}// 初始化进程
void worker_process_init(int worker)
{cpu_set_t cpu_affinity;// worker = 2;// 多核高并发处理 4core 0 - 0 core 1 - 1 2 -2 3 -3CPU_ZERO(&cpu_affinity); // 结构体清零// CPU_SETSIZE:1024 支持cpu最大的数量CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3 设置核/*在多CPU系统中,通过sched_setaffinity ()可以设置进程的CPU亲和力,使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。*/if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1){fprintf(stderr, "sched_setaffinity() failed\n");}
}
查看进程对应的核数
代码中函数指针不太理解的看看下方代码:
// typedef 返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int);
PTRFUN pFun;
char glFun(int a){ return;}
void main()
{ pFun = glFun; (*pFun)(2); //调用函数
}
查看进程在cpu的核上执行的命令: ps -eLo ruser,pid,lwp,psr,args
孤儿僵尸守护进程
孤儿进程:
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
想想我们如何模仿一个孤儿进程? 答案是: kill 父进程!
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(){int fpid = 1;// 父子进程不共享局部变量for(int i = 5 ; i > 0 && fpid > 0 ; i--){fpid = fork();}if(fpid < 0){printf("创建子进程失败\n");return fpid;}else if(fpid == 0){while(1);}else if(fpid > 0){while(1);}return 0;
}
守护进程(重点)
把孤儿进程做成守护进程
不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。守护进程脱离于终端,是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断(比如关闭终端等)。那如何成为一个守护进程呢? 步骤如下:
- 1.调用fork(),创建新进程,它会是将来的守护进程.
- 2.在父进程中调用exit(父进程挂掉),保证子进程不是进程组长
- 3.调用setsid()创建新的会话区 – 具体先不追究
- 4.将当前目录改成根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载他作为守护进程的工作目录)
- 5.将标准输入,标准输出,标准错误重定向到/dev/null.
我们来看这个代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>// 一般传入 0 , 0
int daemon(int nochdir, int noclose)
{int fd = 0;switch (fork()){case -1:return (-1);case 0:break;default:_exit(0); // 父进程自杀}if (setsid() == -1) // 创建会画return (-1);if (!nochdir) // 将当前目录改成根目录(void)chdir("/");if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1){// 重定向 标准输入 标准输出 标准出错(void)dup2(fd, STDIN_FILENO);(void)dup2(fd, STDOUT_FILENO);(void)dup2(fd, STDERR_FILENO);if (fd > 2)(void)close(fd);}return (0);
}int main()
{// 创建子进程,并且把父进程杀死daemon(0,0);printf("hello\n");while(1);// 处理事务return 0;
}
父进程自杀后,守护进程 init 接管 , 一直在后台进行运行
僵尸进程:
一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
- 僵尸进程怎样产生的:
- 一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
- 它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了, 那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。
1.怎么查看僵尸进程:
利用命令ps,可以看到有标记为的进程就是僵尸进程。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main(){pid_t fpid = fork();if(fpid < 0){printf("创建子进程失败\n");return fpid;}else if(fpid == 0){exit(-1);}else if(fpid > 0){while(1);}return 0;
}
这里可以用 wait 和 waitpid 函数回收子进程
2.怎样来清除僵尸进程:
- 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用 wait,内核也会向它发送SIGCHLD消息,尽管对默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
- 把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程。它产生的所有僵尸进程也跟着消失。
相关文章:

linxu学习之进程
文章目录进程程序和进程产生进程销毁进程多进程高并发设计孤儿僵尸守护进程孤儿进程:守护进程(重点)僵尸进程:进程 程序和进程 操作系统可以运行多个程序,那他是如何运行的?实际上,CPU的执行是很快的,而待…...
蓝桥杯真题2
[蓝桥杯 2013 省 B] 连号区间数 题目描述 小明这些天一直在思考这样一个奇怪而有趣的问题: 在 111 ~ NNN 的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是: 如果区间 [L,R][L, R][L,R] 里的所有元素(即此排列的…...

PWM互补输出,以及死区时间计算
本文基于野火例程进行解说 实验内容 本次实验输出一对互补的pwm波,且进行死区时间的计算说明。 代码 互补输出对应的定时器初始化代码: bsp_advance_tim.c /********************************************************************************* fi…...

基于深度学习的海洋动物检测系统(Python+YOLOv5+清新界面)
摘要:基于深度学习的海洋动物检测系统使用深度学习技术检测常见海洋动物,识别图片、视频和实时视频中的海洋动物,方便记录、展示和保存结果。本文详细介绍海洋动物检测系统,在介绍算法原理的同时,给出Python的实现代码…...
C# 计算方差
50,100,100,60,50 计算他们的方差 为了计算这些数的方差,需要进行以下步骤: 1. 计算平均值,即将这些数相加,然后除以它们的数量。 平均值 (50 100 100 60 50) / 5 72 2. 计…...

HJZS电源监视继电器HJZS-E202 AC220V
系列型号: HJZS-E202断电延时继电器 HJZS-E002断电延时继电器 一 应用 HJZS-E202电源监视继电器用于直流或交流操作的各种保护和自动控制的装置中,用以增加触点数量。 二 安装结构 导轨安装9壳体结构,具体尺寸参阅外型尺寸图。 三 产品型号…...

dolphinscheduler 2.0.6 资源中心改造方案二:通过NFS挂载共享目录
目录调度资源中心存储概要安装NFS服务器客户端调度验证关闭SFTP开关(可忽略)重新上传资源文件worker执行任务验证服务器woker客户端worker其它nfs共享目录的配置文件/etc/exports说明调度资源中心存储概要 针对现有的单机存储可以做哪些扩展?…...

基于集成学习的用户流失预测并利用shap进行特征解释
基于集成学习的用户流失预测并利用shap进行特征解释 小P:小H,如果我只想尽可能的提高准确率,有什么好的办法吗? 小H:优化数据、调参侠、集成学习都可以啊 小P:什么是集成学习啊,听起来就很厉害的…...

【Java版oj 】 day17杨辉三角形的变形、计算某字符出现次数
目录 一、杨辉三角形的变形 (1)原题再现 (2)问题分析 (3)完整代码 二、计算某字符出现次数 (1)原题再现 (2)问题分析 (3)完整代…...
智能驾驶芯片赛道混战:如何看待5类玩家的竞争格局?
智能驾驶芯片赛道,一直是业内关注的焦点。 高工智能汽车注意到,针对L0-L2,业内基本采用智能前视一体机(IFC)方案;要实现高速NOA、城市NOA等更为高阶的智驾功能等,则基本采用域控制器方案。从IF…...

vue antd table表格的增删改查(三)input输入框根据关键字模糊查询【后台管理系统 使用filter与indexOf嵌套】
vue antd table表格的增删改查(三)input输入框根据关键字查询【后台管理系统filter与indexOf嵌套】知识回调场景复现利用filter和indexOf方法实现模糊查询1.查询对象为单层的数组元素2.查询对象为多层的数组元素(两层为例)3.查询对…...
【计组】性能指标——速度
衡量计算机性能的指标之一——速度,是指计算机执行完所有指令所耗费时间的长短。 一、概念: 引出了如下概念:机器字长:指计算机一次能处理的二进制位数,也就是我们通常说的32位64位计算机中的位。 机器字长决定了计算…...

【PC自动化测试-4】inspect.exe 详解
1,inspect.exe图解" 检查 "窗口有几个主要部分:● 标题栏。 显示" 检查 HWND (窗口句柄) 。● 菜单栏。 提供对 检查功能 的访问权限。● 工具 栏。 提供对 检查功能 的访问权限。● 树视图。 将 UI 元素的层次结构呈现为树视图控件&…...

比肩ChatGPT的国产AI:文心一言——有话说
🔗 运行环境:chatGPT,文心一言 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 #### 防伪水印——左手の明天 #### 💗 大家好&am…...
【第13届蓝桥杯】C/C++组B组省赛题目+详解
A.九进制转十进制 题目描述 九进制正整数(2022)9转换成十进制等于多少? 解: 2*9^02*9^12*9^321814581478; B.顺子日期 题目描述 小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456等。顺子日期指的就是在日期的yyyymmdd表示法中&a…...

STM32 KEI 调试新手注意事项
记录一下解决问题的经过:1,用STM32 cubeMX 生成的MKD工程,默认的代码优化级别是level3 , 这个级别 会把一些代码给优化掉,造成一些意想不到的结果,最直观的就是 被优化的语句不能打断点调试,当你打了断点 ,…...

Windows权限提升—令牌窃取、UAC提权、进程注入等提权
Windows权限提升—令牌窃取、UNC提权、进程注入等提权1. 前言2. at本地命令提权2.1. 适用范围2.2. 命令使用2.3. 操作步骤2.3.1. 模拟提权2.3.2. at配合msf提权2.3.2.1. 生成木马文件2.3.2.2. 设置监听2.3.2.3. 设置反弹2.3.2.4. 查看反弹效果3. sc本地命令提权3.1. 适用范围3.…...

不做孔乙己也不做骆驼祥子
对教书育人的探讨前言一、为什么要“育人”1.育人为先2.育人是快乐的二、怎么“育人”前言 借着本次师德师风建设的主题,跟各位老师谈一谈对于“育人”的一些观点,和教育的一些看法。本文仅代表自己的观点,有不到位的地方,大家可以…...

ChatGPT原理解析
文章目录Transformer模型结构构成组件整体流程GPT预训练微调模型GPT2GPT3局限性GPT4相关论文Transformer Transformer,这是一种仅依赖于注意力机制而不使用循环或卷积的简单模型,它简单而有效,并且在性能方面表现出色。 在时序模型中&#…...
常用算法实现【必会】:sort/bfs/dfs
文章目录常用排序算法实现(Go版本)BFS 广度优先遍历,利用queueDFS 深度优先遍历,利用stack前序遍历(根 左 右)中序遍历(左根右)后序遍历(左 右 根)BFS/DFS 总…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...
ffmpeg(三):处理原始数据命令
FFmpeg 可以直接处理原始音频和视频数据(Raw PCM、YUV 等),常见场景包括: 将原始 YUV 图像编码为 H.264 视频将 PCM 音频编码为 AAC 或 MP3对原始音视频数据进行封装(如封装为 MP4、TS) 处理原始 YUV 视频…...