IO进程——进程引入、进程函数接口

一、引入

1、进程&程序

1.1 程序

编译好的可执行的文件

存放在磁盘上的指令和数据的有序集合(文件)

程序是静态的,没有任何执行的概念

1.2 进程

一个独立的可调度的任务

执行一个程序所分配的资源的总称

进程是程序执行的一次过程

进程是动态的,包括创建、调度、执行和消亡

2、进程特点

(1)系统会为每一个进程分配0-4g的虚拟空间,0-3g(用户空间)是每个进程所独有的,3-4g(内核空间)是所有进程共有的 (32位系统)

进程间通信

==>

(2)CPU调度进程时会给进程分配时间片(几毫秒~十几毫秒),当时间片用完之后,CPU再去进行其他进程的调度,实现进程的轮转,从而实现多任务操作

没有外界干预的情况下,CPU随机分配调度进程,也就是先调度谁后调度谁随机

进程控制块task_struct(了解)

进程控制块pcb:包含描述进程的相关信息

进程标识PID:唯一的标识一个进程

主要进程标识:

进程号(PID: Process Identity Number)

父进程号:(Parent Process ID: PPID)

进程用户

进程状态、优先级

文件描述符(记录当前进程打开的文件)

3、进程段

Linux中的进程大致包含三个段:

数据段存放的是全局变量、常数以及动态数据分配的数据空间(如malloc函数取得的空间)等。

正文段:存放的是程序中的代码

堆栈段存放的是函数的返回地址、函数的参数以及程序中的局部变量 (类比内存的栈区)

4、分类

交互进程(了解)该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类进程会立刻响应,典型的交互式进程有:shell命令进程、文本编辑器等

批处理进程(了解)该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。(目前接触不到)

守护进程:该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。

5、进程状态

D uninterruptible sleep (usually IO) 不可中断的睡眠态

R running or runnable (on run queue) 运行态

S interruptible sleep (waiting for an event to complete) 可中断的睡眠态

T stopped by job control signal 暂停态

t stopped by debugger during the tracing 因为调试而暂停

X dead (should never be seen) 死亡态

Z defunct ("zombie") process, terminated but not reaped by its parent 僵尸态

< high-priority (not nice to other users) 高优先级

N low-priority (nice to other users) 低优先级

L has pages locked into memory (for real-time and custom IO) 锁在内存中

s is a session leader 会话组组长

l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)多线程

+ is in the foreground process group 前台进程

没有+时,默认是后台进程

I (大写i)空闲状态进程

6、进程状态切换图

        进程创建后,进程进入就绪态,当CPU调度到此进程时进入运行态,当时间片用完时,此进程会进入就绪态,如果此进程正在执行一些IO操作(阻塞操作)会进入阻塞态,完成IO操作(阻塞结束)后又可进入就绪态,等待CPU的调度,当进程运行结束即进入结束态。

什么是阻塞和非阻塞?

阻塞(blocking)、非阻塞(non-blocking):可以简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,在等待的过程中可以做其它事情。否则就可以理解为非阻塞。

7、进程相关命令

ps 查看系统中的进程-ef -aux

top 动态查看系统中运行的进程

renice 修改正在运行进程的优先级

nice 以用户指定的优先级运行进程

kill 给进程发送信号

fg 将进程切换到前台执行

bg 将进程切换到后台执行

jobs 查看当前终端的后台进程

补充:优先级调度

根据进程的优先级进行调度,优先级高的进程先执行。

两种类型:

1、非剥夺式(非抢占式)优先级调度算法。当一个进程正在处理上运行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在进行的进程继续运行,直到由于其自身原因而主动让出处理机(任务完成或等待事件),才把处理机分配给更为重要或紧迫的进程。

2、剥夺式(抢占式)优先级调度算法。当一个进程正在处理机上运行时,若有某个更为重要或紧迫的进程进入就绪队列,则立即暂停正在运行的进程,将处理机分配给更重要或紧迫的进程。

笔试题:

1、下列关于轮询任务调度和可抢占式调度区别描述错误的是?( D )

A. 抢占式调度实现相对较复杂且可能出现低优先级的任务长期得不到调度

B. 轮询调度不利于后面的请求及时得到响应

C. 抢占式调度有利于后面的高优先级的任务也能及时得到响应

D. 抢占式调度优点是其简洁性,它无需记录当前所有连接的状态

解析:抢占式调度相对复杂,需要记录和管理任务的优先级、状态等信息

2、会导致进程从执行态变为就绪态的事件是( D )。

A. 执行P(wait)操作

B. 申请内存失败

C. 启动I/O设备

D. 被高优先级进程抢占

3、分配到必要的资源并获得处理机时的进程状态是( B )。

A. 就绪状态

B. 执行状态

C. 阻塞状态

二、进程函数接口

1、创建子进程

#include <sys/types.h>

#include <unistd.h>

pid_t fork(void);

功能:创建子进程

返回值:

成功:

在父进程中 ===> 返回子进程的进程号 >0

在子进程中 ===> 返回值为0

失败:-1并设置errno

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{// 创建子进程,子进程中返回0,父进程返回子进程的PIDpid_t pid = fork();    if (pid < 0)    // 容错判断{perror("fork err");return -1;}else if (pid == 0)    // 子进程printf("child\n");else    // 父进程printf("parent\n");while (1);    // 让父子进程都进入死循环不结束return 0;
}

        解释:./a.out会启动一个进程,执行到fork()函数时会在当前进程中创造了一个子进程并把代码以及数据信息拷贝到子进程,这两个进程只有个别数据例如进程号以及fork的返回值不一样,此时这两个进程由CPU随机调度。注意!!子进程会得到fork函数返回值然后执行fork之后的代码,fork函数之前的代码不会执行

●特点

1)子进程几乎拷贝了父进程的全部内容。包括代码、数据、系统数据段中的pc值、栈中的数据、父进程中打开的文件等;但它们的PID、PPID是不同的。

2父子进程有独立的地址空间,互不影响;当在相应的进程中改变全局变量、静态变量,都互不影响。

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{int a = 10;    // 定义变量apid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0){        a = 20;    // 子进程中修改了a的值,不会影响父进程中a的值printf("child:%d, ip:%p\n", a, &a);}elseprintf("parent:%d, ip:%p\n", a, &a);while (1);return 0;
}

3)若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程。

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0)    // 子进程{        printf("child\n");while (1);    // 让父进程先结束,子进程先不结束}else    // 父进程printf("parent\n");return 0;
}

4)若子进程先结束,父进程如果没有及时回收资源,子进程变成僵尸进程(要避免僵尸进程产生)

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0)    // 子进程 printf("child\n");else    // 父进程{        printf("parent\n");while (1);    // 让子进程结束,父进程不结束} return 0;
}

2、回收资源

2.1 wait

#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *status);

功能:回收子进程资源(阻塞父进程)

参数:

status ===> 子进程退出状态,不接受子进程状态设为NULL

返回值:成功:回收的子进程的进程号 失败:-1

#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0)    // 子进程 {        printf("child\n");sleep(3);    // 子进程睡眠3秒后再结束}else    // 父进程{        printf("parent\n");wait(NULL);   // 阻塞父进程等待回收子进程资源,子进程结束后才能结束阻塞成功回收printf("after wait\n");while (1);} return 0;
}

运行程序并查看进程状态,此时会发现没有僵尸态进程

2.2 waitpid

#include <sys/types.h>

#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

功能:回收子进程资源

参数:pid

>0 指定子进程进程号

=-1 任意子进程

=0 等待其组ID等于调用进程的组ID的任一子进程

<-1 等待其组ID等于pid的绝对值的任一子进程

status ===> 子进程退出状态

options ===> 0:阻塞 WNOHANG:非阻塞

返回值:正常:结束的子进程的进程号

当使用选项WNOHANG且没有子进程结束时:0

出错:-1

#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0)    // 子进程 {        printf("child\n");sleep(3);    // 子进程睡眠3秒后再结束}else    // 父进程{        printf("parent\n");  // waitpid(-1, NULL, 0);    /*0代表阻塞接收子进程资源,此时和wait(NULL)一样*/waitpid(-1, NULL, WNOHANG); // WNOHANG:代表非阻塞printf("after wait\n");        while (1);} return 0;
}

2.3 练习

实现waitpid设置非阻塞WNOHANG也可以接收到子进程资源

#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{int n = 0;pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0)  // 子进程  {        printf("child\n");sleep(3);    // 子进程睡眠3秒以后结束}else    // 父进程{        printf("parent\n");while (1)    // 使用轮询{// 直到接收到子进程资源则退出循环if (waitpid(-1, NULL, WNOHANG) > 0)break;}while (1);} return 0;
}
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include<stdio.h>
int main(int argc, char const *argv[])
{int n = 0;pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0)  // 子进程  {        printf("child\n");sleep(3);}else    // 父进程{        printf("parent\n");while ((n = waitpid(-1, NULL, WNOHANG)) <= 0){if (n == -1)return -1;}while (1);} return 0;
}

3、结束进程

3.1 exit

#include <stdlib.h>

void exit(int status);

功能:结束进程,刷新缓存

#include<stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{printf("hello");exit(0);    // 刷新缓存while (1);return 0;
}

3.2 _exit

#include <unistd.h>

void _exit(int status);

功能:结束进程,不刷新缓存

参数:status是一个整型的参数,可以利用这个参数传递进程结束时的状态。

通常0表示正常结束;

其他的数值表示出现了错误,进程非正常结束

#include<stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{printf("hello");_exit(0);    // 不刷新缓存while (1);return 0;
}

3.3 return和exit区别

#include<stdio.h>
int fun()
{printf("in fun\n");return 0;    // 结束当前函数,in main还会正常显示
}
int main(int argc, char const *argv[])
{fun();printf("in main\n");return 0;
}

#include<stdio.h>
#include<stdlib.h>
int fun()
{printf("in fun\n");exit(0);    // 直接结束进程,in main不会显示
}
int main(int argc, char const *argv[])
{fun();printf("in main\n");return 0;
}

接收子进程退出的状态

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) //子进程{printf("child\n");exit(0);    // 代表正常退出,返回0}else //父进程{int s;printf("parent\n");wait(&s);printf("%d\n", s);}return 0;
}

4、获取进程号

4.1 获取PID

#include <sys/types.h>

#include <unistd.h>

pid_t getpid(void);

功能:获取当前进程的进程号

4.2 获取PPID

#include <sys/types.h>

#include <unistd.h>

pid_t getppid(void);

功能:获取当前进程的父进程号

4.3 举例

#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) //子进程printf("child中pid:%d ppid:%d\n", getpid(), getppid());else //父进程printf("parent中子进程pid:%d pid:%d\n", pid, getpid());while (1);return 0;
}

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

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

相关文章

周末游戏推荐:安卓端俄罗斯方块,经典与创新的结合

前段时间&#xff0c;每到周末我都会给大家推荐一些离线的经典游戏&#xff0c;原本打算将这个传统一直延续下去。然而&#xff0c;我实在找不到足够好用且无广告的游戏了。有些游戏刚开始用的时候还不错&#xff0c;但用着用着就开始频繁弹出广告&#xff0c;这让我实在不敢向…

《用 Scikit-learn 构建 SVM 分类模型:从原理到实战的全流程解析》

《用 Scikit-learn 构建 SVM 分类模型:从原理到实战的全流程解析》 一、引言:为什么选择 SVM? 在机器学习的众多算法中,支持向量机(SVM)以其强大的分类能力和良好的泛化性能,在文本分类、人脸识别、医学诊断等领域广泛应用。尤其在中小规模数据集上,SVM 往往能提供比…

一文学会CMakeLists.txt: CMake现代C++跨平台工程化实战

你能学到什么&#xff1f;朋友们好久不见&#xff0c;我是alibli&#xff0c;好久没有更新博客了。今天本人将通过构造一个实际的虚拟小项目&#xff0c;来让你彻底掌握CMake跨平台工程构建&#xff0c;学会CMakeLists.txt语法。该项目实现了一个简单的平方、立方的计算程序&am…

高并发场景下限流算法实践与性能优化指南

高并发场景下限流算法实践与性能优化指南 在大规模并发访问环境中&#xff0c;合理的限流策略能保护后端服务稳定运行&#xff0c;避免系统因瞬时高并发导致资源耗尽或崩溃。本文将从原理出发&#xff0c;深入解析几种主流限流算法&#xff0c;并结合Java和Redis给出完整可运行…

Vue3应用执行流程详解

精确化的完整执行流程 (以 Vite Vue3 SPA 为例)整个过程可以分为两部分&#xff1a;首次访问的“冷启动”和后续的Vue应用接管。第一部分&#xff1a;首次访问与页面加载客户端&#xff1a;发送请求用户打开浏览器&#xff0c;输入 URL&#xff08;如 http://localhost:5173&a…

Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)

这篇是我把几套生产环境踩坑与复盘整理成的一份“从 0 到 1 长期可维护”的实践文。目标是&#xff1a;明确策略、给出默认可用的配置模板、把常见坑一次讲透。 适用场景&#xff1a;新项目选型、老项目稳定性加固、从单机迁移到 HA/Cluster、应对数据安全与故障切换要求。目录…

Linux内核的PER_CPU机制

参考书《Linux内核模块开发技术指南》 1.原理 在多核CPU的情况下&#xff0c;为了提高CPU并发执行的效率&#xff0c;对于某些不是必须要在核间进行同步访问的资源&#xff0c;可以为每一个CPU创建一个副本&#xff0c;让每个CPU都访问自身的数据副本&#xff0c;而不是通过加锁…

VSCode 的百度 AI编程插件

VSCode 的百度 AI编程插件主要是 Baidu Comate&#xff08;文心快码&#xff09;&#xff0c;这是一款基于文心大模型的新一代编码辅助工具&#xff0c;旨在提升开发者的编码效率&#xff0c;让写代码变得更简单。以下是关于 Baidu Comate 的详细介绍&#xff1a; 一、功能特点…

阿里云监控使用

阿里云的云监控服务&#xff08;CloudMonitor&#xff09;是一款简单易用、功能强大的监控工具&#xff0c;主要用来帮助用户实时监控阿里云上的各种资源&#xff08;比如服务器、数据库、网络等&#xff09;&#xff0c;并在出现问题时及时发出警报&#xff0c;确保业务稳定运…

嵌入式C语言-关键字typedef

定义和作用 typedef是C/C中的一个关键字&#xff0c;作用是为现有的数据类型&#xff08;int 、char 、flaot等&#xff09;创建新的别名&#xff0c;其目的是为了方便阅读和理解代码。 用法 typedef 原有类型名 新类型名;基本类型创建别名 typedef unsigned char uint8_t; typ…

【混合开发】【大前端++】Vue节点优化Dome之单节点轮播图片播放视频二

动图更精彩 背景 Vue作为大前端开发页面交互&#xff0c;在数字屏&#xff0c;智慧大屏等大屏幕开发过程中&#xff0c;轮播效果作为丰富的展示组件经常作为首选。但也因为这个组件的交互体验很好&#xff0c;于是各种单点组件增加到轮播效果里。经过业务的扩展&#xff0c;人…

前端开发核心技术与工具全解析:从构建工具到实时通信

觉得主包文章可以的,可以点个小爱心哟&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 主页:一位搞嵌入式的 genius-CSDN博客 系列文章专栏: https://blog.csdn.net/m0_73589512/category_13028539.html 前端开发核心技术与工具全解…

GPT 系列论文 gpt3-4 175B参数 + few-shot + 多模态输入 + RLHF + system

GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【论文精读】 GPT-4论文精读 从1750亿参数的文本预言家&#xff0c;到多模态的通用天才&#xff0c;OpenAI用两次震撼世界的发布&#xff0c;重新定义了人工智能的可能性边界。这份笔记将带你深入GPT-3和GPT-4的核心突破&#…

.gitignore文件的作用及用法

目录 ​​.gitignore 文件的作用​​ ​​.gitignore 的基本语法​​ ​​Python 项目的 .gitignore 示例​​ ​​如何使用 .gitignore​​ ​​1. 创建 .gitignore 文件​​ ​​2. 编辑 .gitignore​​ ​​3. 检查 Git 状态​​ ​​常见问题​​ ​​Q1&#xff…

QEMU环境准备

QEMU环境准备 下载 qemu # qemu sudo apt install qemu-system-arm # gdb sudo apt install gdb-multiarchsudo apt-get update sudo apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev \libpixman-1-dev libfdt-dev ninja-build下载并自行编译 qemu(可…

003 cargo使用

cargo是什么 cargo 是 Rust 的构建系统和包管理器。Rust 开发者常用 cargo 来管理 Rust 工程和获取工程所依赖的库。 在上一篇文章中我们已经使用cargo new命令创建了一个名叫hello_rust的项目。也使用cargo run来运行项目。 cargo常用命令 cargo 除了创建工程以外还具备构建&a…

跨省跨国监控难题破解:多层级运维的“中国解法”

在全球化的商业浪潮中&#xff0c;集团型客户的业务布局日益广泛&#xff0c;涉及跨省甚至跨国的多个分支机构和业务节点。这种跨域管理的模式给企业的运维监控带来了前所未有的挑战。多个分支机构和业务节点运维调整首先&#xff0c;不同地区的网络环境差异巨大。从国内不同省…

pandas读取复合列名列头及数据和处理

pandas读取复合列名列头及数据和处理1. 效果图2. 源代码1. 效果图 原始excel&#xff1a; 读取1&#xff0c;2行为复合表头&#xff1a; 读取序号为1003一整行的数据&#xff0c;以及获取序号为1002行及1003行的C列复合表头列的值&#xff1a; 2. 源代码 import pandas …

制作一个简单的vscode插件

当前环境情况 操作系统&#xff1a;Windows 项目类型&#xff1a;VS Code 插件&#xff08;TypeScript 编写&#xff09; Node.js 版本&#xff1a;20.18.1 yarn 版本&#xff1a;1.22.22 npm 版本&#xff1a;10.8.2 npm registry&#xff1a;huawei ------- https://repo.hua…

分布式专题——10.2 ShardingSphere-JDBC分库分表实战与讲解

1 分库分表案例 下面实现一个分库分表案例&#xff0c;将一批课程信息分别拆分到两个库&#xff0c;四个表中&#xff1a; 需提前准备一个 MySQL 数据库&#xff0c;并在其中创建 Course 表。Course 表的建表语句如下&#xff1a; CREATE TABLE course (cid bigint(0) NOT N…