IO进程线程(六)进程

文章目录

  • 一、进程状态
    • (二)进程状态切换实例
      • 1. 实例1
  • 二、进程的创建
    • (一)原理
    • (二)fork函数--创建进程
      • 1. 定义
      • 2. 不关注返回值
      • 3. 关注返回值
    • (三) 父子进程的执行顺序
    • (四)父子进程内存空间
    • (五)使用实例
  • 三、 getpid/getppid
  • 四、孤儿进程
  • 五、僵尸进程
  • 三、进程退出exit/_exit函数
    • (一)exit
    • (二)_exit
  • 四、进程回收资源
    • (一)wait
    • (二)waitpid

一、进程状态

可通过 man ps 查看

R (runing or runnable) 运行态或者可被运行态(在运行队列中)
S (interruptible sleep) 可被中断的休眠态
D (uninterruptible sleep) 不可被中断的休眠态
T (stopped by job control signal) 停止态
Z (("zombie") process)僵尸态
X (dead ) 死亡态(永远不会被看到)
I (Idle kernel thread) 空闲内核线程

进程的附加状态:

<    高优先级的进程
N    低优先级的进程
s    (session leader)会话组组长
l    (multi-threaded)进程中包含多线程
+    前台进程组的进程
L    有页在内存中被锁定

(二)进程状态切换实例

1. 实例1

#include <stdio.h>int main(int argc, char const *argv[])
{int i=0;while(1){printf("%d\n",i++);sleep(1);}return 0;
}

该程序运行时,大部分时间在休眠,处于休眠态

./a.out 运行 ------ 前台运行
在这里插入图片描述
想让一个进程在后台运行
可以 在运行进程的命令后面加一个 &./a.out &
在这里插入图片描述

  • 注:
  • 前台运行时,终端会被该进程占用,无法继续接收命令
  • 后台运行时,终端会被释放出来,可以接收命令
  • 处于后台运行时,无法直接“CTRL+C”来结束进程,需要发送kill -19 pid

可以使用 kill -19 pid 给进程发19号信号让进程停止(T停止态)
也可以使用 ctrl+z 来停止进程(相当于给进程发kill -20 pid)
被停止的进程的终端上使用 jobs -l 可以查看进程的作业号

  • 注:此处必须在被停止的进程的终端上查看,其他终端无法查看
    在这里插入图片描述

fg 作业号 让停止的进程继续在前台运行
在这里插入图片描述
bg 作业号 让停止的进程继续在后台运行
kill -18 pid 让停止的进程继续在后台运行
在这里插入图片描述

二、进程的创建

(一)原理

进程的创建是通过 完全 拷贝父进程来实现的,子进程所有资源都来自于父进程。
子进程创建成功后,父子进程的执行相互独立

(二)fork函数–创建进程

1. 定义

#include <sys/types.h>
#include <unistd.h>pid_t fork(void);功能:拷贝父进程,产生子进程参数:无返回值:成功  给父进程返回子进程的PID 给子进程返回 0失败  -1  不会创建子进程   会重置错误码

2. 不关注返回值

在不考虑返回值时,调用n次fork函数,会产生2^n个进程(包含父进程)

#include <my_head.h>int main(int argc, char const *argv[])
{for(int i=0;i<2;i++){fork();printf("#"); }return 0;
}

输出结果
在这里插入图片描述

分析结果
要注意此处printf中并没有\n,即打印的’#‘存放在输出缓冲区中,而在循环第二次执行时,fork函数通过拷贝父进程生成子进程,即将其缓冲区也进行了拷贝,因此打印出了8个’#’

#include <my_head.h>int main(int argc, char const *argv[])
{for(int i=0;i<2;i++){fork();printf("#\n");}return 0;
}

输出结果
在这里插入图片描述
分析结果
要注意此处printf中有\n,此时的’#‘直接打印到了终端上,而在循环第二次执行时,fork函数通过拷贝父进程生成子进程,其缓冲区内是空的,直接又各自执行了一次打印操作,因此打印出了6个’#’

3. 关注返回值

fork函数给父进程返回子进程的pid,给子进程返回0,因此通过pid进行条件判断。
pid>0,说明当前进程是父进程;pid==0,说明当前进程是子进程,由此来使其执行各自的程序。

#include <my_head.h>int main(int argc, char const *argv[])
{printf("-----start-----\n");pid_t pid=fork();if(-1 == pid){ERR_LOG("fork error");}else if(0 < pid){printf("这是父进程\n");}else if(0 == pid){printf("这是子进程\n");}printf("-----end-----\n");return 0;
}

在这里插入图片描述

(三) 父子进程的执行顺序

父子进程执行,没有先后顺序,也是时间片轮转,谁得到cpu谁执行

(四)父子进程内存空间

父进程在fork产生子进程时,用到了写时拷贝的原则
如果父子进程中如果都只对同一个变量有读操作,那么不会重新映射到不同的物理内存;
只有在父子进程的中的任意一方执行了写操作时,才会重新映射到不同的物理内存
在这里插入图片描述

(五)使用实例

功能需求:使用父子进程拷贝文件,提高拷贝效率
因为cpu在执行程序时是按照时间片轮转的方式,哪个进程得到cpu就在这个时间片执行程序,而使用父子进程同时拷贝,就相当于增加了时间片轮转轮到的概率,由此提高拷贝效率。

需求分析
fork之前打开的文件,fork之后,父子访问文件时是共用光标的。
如果不想让光标共用,可以在fork之后,父子进程中分别使用open去打开文件。

将源文件和目标文件一分为二,父进程复制文件开头到中间的位置的内容,子进程复制文件中间位置到结尾的内容,两个进程分别打开文件,不共用文件标识符

  • 补充:关于可否使用父子进程在打开的文件中共用光标来实现拷贝的可实现性:
    不能保证在一个时间片段内可以完整的执行完一条机器指令;因此可能会出现以下情况,如父进程读取了一段内容后,准备执行光标后移,但是未完成光标后移时就发生了时间片轮转,接着子进程再次复制时,光标并未移动,而重复读取内容。

代码实现

#include <my_head.h>int main(int argc, char const *argv[])
{if(3 != argc){printf("Usage:%s src dest\n",argv[0]);exit(-1);}//获取文件大小struct stat file_stat;if(-1 == stat(argv[1],&file_stat))ERR_LOG("stat error");int size = file_stat.st_size;char buff[10]={0};int nbyte=0;int w_byte=0;//创建子进程pid_t pid=fork();if(-1==pid){ERR_LOG("fork error");}else if(0 < pid){//父进程//打开文件,从文件开头int src_fd = open(argv[1],O_RDONLY);int dest_fd = open(argv[2],O_WRONLY|O_CREAT,0666);//复制while(0 < (nbyte = read(src_fd,buff,sizeof(buff)))){write(dest_fd,buff,nbyte);//判断是不是写了一半w_byte=w_byte+nbyte;if(w_byte >= size/2) break;}//关闭文件close(src_fd);close(dest_fd);sleep(1);//等待子进程结束}else if(0 == pid){//子进程//打开文件,从文件中间int src_fd = open(argv[1],O_RDONLY);lseek(src_fd,size/2,SEEK_SET);int dest_fd = open(argv[2],O_WRONLY|O_CREAT,0666);lseek(dest_fd,size/2,SEEK_SET);//复制while(0 < (nbyte = read(src_fd,buff,sizeof(buff)))){write(dest_fd,buff,nbyte);}//关闭文件close(src_fd);close(dest_fd);}return 0;
}

三、 getpid/getppid

#include <sys/types.h>
#include <unistd.h>pid_t getpid(void);功能:返回调用进程的pid
参数:无
返回值:总是会成功pid_t getppid(void);功能:返回调用进程的父进程pid
参数:无
返回值:总是会成功

eg:使用fork创建进程,A创建B,B创建C,在每个进程中打印pid和ppid。

#include <my_head.h>int main(int argc, const char *argv[])
{pid_t pid = fork();if(-1 == pid){ERR_LOG("fork error");}else if(0 < pid){sleep(3);printf("我是A  pid = [%d]  ppid = [%d]\n", getpid(), getppid());}else if(0 == pid){if(-1 == (pid = fork())){ERR_LOG("fork error");}else if(0 < pid){sleep(1);printf("我是B  pid = [%d]  ppid = [%d]\n", getpid(), getppid());}else if(0 == pid){printf("我是C  pid = [%d]  ppid = [%d]\n", getpid(), getppid());}}return 0;
}

四、孤儿进程

子进程还没有执行完,父进程就结束了,此时子进程就是孤儿进程
孤儿进程会被 init 进程收养,当孤儿进程结束时 init 给他回收资源

孤儿进程就是一个正常的进程,当只不过其父进程变成了init。
他并不是进程状态的一种。

五、僵尸进程

当子进程运行结束后,父进程没有为其回收资源,此时子进程就是僵尸进程
僵尸进程对系统有害,占着资源不释放

三、进程退出exit/_exit函数

(一)exit

  • 注:
  • return 本身不使用来结束进程的,而是用来结束函数调用的,
  • 只有在main函数中执行到return 才会结束整个进程 而在子函数中实行return只会结束函数调用
#include <stdlib.h>void exit(int status);功能:他是一个库函数,用来结束进程,他会刷新缓冲区参数:status:给父进程返回的进程退出状态值 (0-255)#define EXIT_FAILURE    1#define EXIT_SUCCESS    0返回值:无

(二)_exit

#include <unistd.h>void _exit(int status);功能:他是一个系统调用,用来结束进程,他不会刷新缓冲区参数:status:给父进程返回的进程退出状态值返回值:无

四、进程回收资源

(一)wait

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *wstatus);功能:wait用于父进程中,用来阻塞等待任意一个子进程退出,给子进程回收资源子进程exit退出时的状态值 会被wait接收到。参数:wstatus:用来保存子进程退出状态的缓冲区的首地址如果不关心子进程退出的状态  可以传 NULL如果使用了:0-67个bit位中保存的是终止子进程的信号的编号8-158个bit位保存的是子进程退出的状态值WIFEXITED(wstatus) 如果为真 说明子进程是正常结束的WEXITSTATUS(wstatus) 如果子进程是正常结束的 可以用它获取子进程退出的状态值WIFSIGNALED(wstatus) 如果为真 说明子进程是被信号中断的WTERMSIG(wstatus)  如果子进程是被信号中断的 可以使用它来获取终止子进程的信号的编号返回值:成功 终止的子进程的pid失败 -1  重置错误码

(二)waitpid

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:等待指定pid的子进程退出,为其回收资源
参数:pid:要回收资源的子进程的pid>0  回收指定pid的子进程的资源-1  回收任意一个子进程的资源0   回收和父进程同组的任意一个子进程的资源<-1 回收任意一个进程组id等于 pid 的绝对值的子进程的资源wstatus:和wait用法一样options:标志位  0 阻塞    WNOHANG 非阻塞
返回值:成功 回收资源的子进程的pid如果设置了 WNOHANG 且没有子进程退出时 返回 0失败  -1  重置错误码

注:
有下面等价的用法:
wait(NULL) <==> waitpid(-1, NULL, 0);
wait(&wstatus) <==> waitpid(-1, &wstatus, 0);

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

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

相关文章

【Redis数据库百万字详解】数据持久化

文章目录 一、持久化1.1、什么是持久化1.2、持久化方式1.3、RDB优缺点1.4、AOF优缺点 二、RDB持久化触发机制2.1、手动触发2.2、自动触发 三、RDB持久化配置3.1、配置文件3.2、配置查询/设置3.3、禁用持久化3.4、RDB文件恢复 四、RDB持久化案例4.1、手动持久化4.2、自动持久化案…

2024第26届大湾区国际电机博览会暨发展论坛

2024第二十六届大湾区国际电机博览会 暨发展论坛 2024第26届大湾区国际电机博览会暨发展论坛 The 26th Greater Bay Area International Motor Expo and Development Forum 时间&#xff1a;2024年12月4-6日 地址&#xff1a;深圳国际会展中心&#xff08;宝安新馆&#x…

安全生产新篇章:可燃气体报警器检验周期的国家标准解读

随着工业化进程的加快&#xff0c;安全生产成为了重中之重。 可燃气体报警器作为预防火灾和爆炸事故的重要设备&#xff0c;其准确性和可靠性直接关系到企业的生产安全和员工的生命财产安全。 因此&#xff0c;国家对可燃气体报警器的检验周期有着明确的规定&#xff0c;以确…

rk3568中断irq

前言 本文记录的是在rk3568开发板通过按键中断的实验了解和学习linux中断irq 一、Linux中断简介 在单片机中,中断的过程: ①、使能中断,初始化相应的寄存器 ②、编写中断服务函数,中断发生以后相应的中断服务函数就会执行。在 Linux 内核中也提供了大量的中断相关的 API …

美洽工作台3.0,全新发布!

美洽工作台3.0&#xff0c;全新发布 想要效率翻倍&#xff0c;就要一步到位&#xff01; 工作台 3.0&#xff0c;为效率而生 1. 更丰富的外观选择&#xff0c;让界面焕然一新&#xff0c;新增导航主题色选择&#xff0c;深色 Dark、浅色 Light 随意切换 2. 自定义你的专属导…

Python 识别图片形式pdf的尝试(未解决)

想识别出pdf页面右下角某处的编号。pdf是图片形式页面。查了下方法&#xff0c;有源码是先将页面提取成jpg&#xff0c;再用pytesseract提取图片文件中的内容。 直接用图片来识别。纯数字的图片&#xff0c;如条形码&#xff0c;可识别。带中文的不可以&#xff0c;很乱。 识别…

[12] 使用 CUDA 加速排序算法

使用 CUDA 加速排序算法 排序算法被广泛用于计算应用中有很多排序算法,像是枚举排序或者说是秩排序、冒泡排序和归并排序,这些排序算法具有不同的(时间和空间)复杂度,因此对同一个数组来说也有不同的排序时间,对于大数组而言,可能会很耗时如果排序算法能用 CUDA 加速,则…

吴恩达深度学习笔记:机器学习(ML)策略(1)(ML strategy(1))1.3-1.4

目录 第三门课 结构化机器学习项目&#xff08;Structuring Machine Learning Projects&#xff09;第一周 机器学习&#xff08;ML&#xff09;策略&#xff08;1&#xff09;&#xff08;ML strategy&#xff08;1&#xff09;&#xff09;1.3 单一数字评估指标&#xff08;S…

Linux|如何安装 Java

引言 Java是最受欢迎的编程语言之一&#xff0c;JVM&#xff08;Java的虚拟机&#xff09;是运行Java应用程序的运行时环境。这两个平台是许多流行软件所需的&#xff0c;包括Tomcat&#xff0c;Jetty&#xff0c;Cassandra&#xff0c;Glassfish和Jenkins。 本教程[1]将指导您…

实验名称:文件数据存储练习

一手好牌硬打。 目录 一、实验目的 二、实验环境 三、实验步骤 四、实验结果 1.图片备份 2.将文件中所有的小写字母转换成大写字母&#xff0c;将所有的大写字转换成小写字母 3.完成班级学生成绩的录入&#xff0c;并保存在csv文件中。 4.获得csv文件中的成绩&#xf…

java 若依框架使用介绍

若依框架是一个开源的后台管理系统&#xff0c;用了2周最大的感觉就是比较轻量级的&#xff0c;有多种不同的版本&#xff0c;如前后端分离、微服务、移动端版本&#xff0c;集成了简单的代码生成器&#xff0c;入门比起jeecgboot要稍微更加简单一些。 官网地址&#xff1a;ht…

2024年应用经济学、管理科学与社会国际学术会议(ICAEMSS 2024)

2024年应用经济学、管理科学与社会国际学术会议&#xff08;ICAEMSS 2024&#xff09; 会议简介 2024年应用经济学、管理科学与社会国际学术会议将聚焦应用经济学和管理科学的前沿问题&#xff0c;深入探讨社会变革中的经济管理与科学应用。参会者将分享最新研究成果&#xf…

短剧小程序App系统源码:打造个性化追剧体验

随着数字媒体的迅猛发展&#xff0c;短剧作为一种新兴的娱乐形式&#xff0c;越来越受到广大观众的喜爱。为了满足用户对短剧内容的个性化需求&#xff0c;短剧小程序App系统应运而生。本文将深入探讨短剧App源码的核心功能&#xff0c;以及如何通过多语言支持和国际支付等技术…

超声波洗眼镜机是智商税吗?四款不能错过的超声波清洗机实力种草

在日常生活中&#xff0c;眼镜成为了我们不可或缺的伙伴&#xff0c;无论是阅读书籍、工作还是享受自然风光&#xff0c;清晰的视野总是至关重要。然而&#xff0c;眼镜上不可避免地会沾染灰尘、油脂甚至细菌&#xff0c;影响我们的视觉体验。传统的眼镜清洗方法虽然简单&#…

雷池WAF《动态防护》功能体验

一、雷池简介&#xff08;官方&#xff09; 自 2016 年起&#xff0c;长亭就开源了雷池的语义分析算法自动机引擎&#xff0c;随后又陆续开源了雷池相关风控插件和引擎通信协议。雷池的商业版本自发布以来&#xff0c;得到了各大咨询机构和众多顶级企业的认可。然而&#xff0…

MT3050 区间最小值

思路&#xff1a; 使用ST表 ST模板可参考MT3024 maxmin 代码&#xff1a; 1.暴力9/10&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e5 10; int n, m; int a[N]; int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin …

Java的垃圾回收算法详解

在Java编程语言中&#xff0c;垃圾回收&#xff08;Garbage Collection, GC&#xff09;是一个至关重要的概念&#xff0c;它负责自动管理内存&#xff0c;释放不再使用的对象所占用的空间&#xff0c;从而防止内存泄漏和溢出。下面我们将从技术难点、面试官关注点、回答吸引力…

2024精选热门骨传导耳机推荐,你不会还不挑选吧?

骨传导耳机作为最近两年来才兴起的耳机品类&#xff0c;在街头的出现频率并不是很高&#xff0c;很多人对骨传导耳机不够了解甚至没听说过。骨传导耳机不入耳的设计&#xff0c;安全性、舒适性和稳定性都更高&#xff0c;既然有这么多的优势&#xff0c;那就为大家挑选几款高性…

leetcode-[704]二分查找[27]移除元素

一、[704]二分查找 //二分法&#xff1a;有序 //[left,right] 故判定条件为left < right,等于此时有意义&#xff1b; //缩小范围 leftmid1&#xff1b; //right nums.length-1; //不要忘了修改mid 的值class Solution {public int search(int[] nums, int target) {int le…

16. 最接近的三数之和 - 力扣

1. 题目 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数&#xff0c;使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 2. 示例 3.分析 做这道题目前&#xff0c;先做这道&#xff1a;三数之和 &#x…