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);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OCP 备份 OceanBase集群

注:OCP版本为4.2.1,OceanBase版本为 社区版4.2.1.0 手动备份 进行合并 在手动进行备份数据之前&#xff0c;建议进行一次OB集群合并(不影响业务的前提下)&#xff0c;关于合并的概念请参考OB官网。 点击进入要备份的OB集群 点击左侧工具栏中的 合并管理&#xff0c;在 基本信息…

【前端基础】CSS介绍|CSS选择器|常用CSS

目录 一、CSS介绍 1.1 什么是CSS 1.2 基本语法规范 1.3 引⼊⽅式 1.4 规范 &#x1f4a1;二、CSS选择器 1. 标签选择器 2. class选择器 3. id选择器 4. 复合选择器 5. 通配符选择器 三、常用CSS 3.1 color 3.2 font-size 3.3 border 3.4 width/height 3.5 padd…

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

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

密塔AI:联网搜索工具,可以搜索科研文献

文章目录 简介功能探究 简介 作为联网搜索AI&#xff0c;肯定得有能力做个自我介绍&#xff0c;在搜索框中输入“密塔AI简介”&#xff0c;其处理过程如下&#xff0c;看来主打一个没有广告&#xff0c;直达结果。 回复如下 秘塔AI搜索(metaso.cn)于2024年初上线&#xff0c;它…

若依 ruoyi-vue element-ui el-cascader 级联选择器 选择任意一级选项,去掉单选按钮,选中点击后隐藏

Cascader 级联选择器 选择任意一级选项&#xff0c;去掉单选按钮。 这兄弟文章写的可以&#xff0c;查了一堆文章&#xff0c;基本搞完才发现。 官方的例子不支持选中后自动关闭&#xff0c;要点击旁边空白&#xff0c;并且单选框太小了。 <el-form-item label"所属地…

CSS双飞翼布局

双飞翼布局是一种经典的CSS布局模式&#xff0c;主要用于实现左右两列固定宽度&#xff0c;中间列自适应的布局。 比如&#xff1a;写一个左中右布局占满全屏&#xff0c;其中左、右两块固定宽 200px&#xff0c;中间自适应&#xff0c;要求先加载中间块。 <!DOCTYPE html…

一文看懂llama2(原理模型训练)

自从Transformer架构问世以来&#xff0c;大型语言模型&#xff08;Large Language Models, LLMs&#xff09;以及AIGC技术的发展速度惊人&#xff0c;它们不仅在技术层面取得了重大突破&#xff0c;还在商业应用、社会影响等多个层面展现出巨大潜力。随着ChatGPT的推出&#x…

Nginx02-Nginx虚拟主机介绍、日志介绍、Location规则介绍

目录 写在前面NginxNginx处理用户请求流程虚拟主机虚拟主机的分类基于域名的虚拟主机基于端口的虚拟主机基于IP的虚拟主机 Nginx日志错误日志案例 访问日志访问格式变量案例 Location规则案例1案例2Location规则小结 写在前面 这是Nginx第二篇&#xff0c;内容为Nginx处理用户请…

【WEB系列】过滤器Filter

Filter&#xff0c;过滤器&#xff0c;属于Servlet规范&#xff0c;并不是Spring独有的。其作用从命名上也可以看出一二&#xff0c;拦截一个请求&#xff0c;做一些业务逻辑操作&#xff0c;然后可以决定请求是否可以继续往下分发&#xff0c;落到其他的Filter或者对应的Servl…

mysql中optimizer trace的作用

大家好。对于MySQL 5.6以及之前的版本来说&#xff0c;查询优化器就像是一个黑盒子一样&#xff0c;我们只能通过EXPLAIN语句查看到最后 优化器决定使用的执行计划&#xff0c;却无法知道它为什么做这个决策。于是在MySQL5.6以及之后的版本中&#xff0c;MySQL新增了一个optimi…

量化投资分析平台 迅投 QMT(三)字典数据下载后读取成Dataframe形式

量化投资分析平台 迅投 QMT [迅投 QMT](https://www.xuntou.net/?user_code7NYs7O)我目前在使用如何读取下载好的数据出来上代码历史帖子 迅投 QMT 我目前在使用 两个月前&#xff08;2024年4月&#xff09;迅投和CQF有一个互动的活动&#xff0c;进行了平台的一个网上路演&…

初始C++(类与对象)

感谢大佬的光临各位&#xff0c;希望和大家一起进步&#xff0c;望得到你的三连&#xff0c;互三支持&#xff0c;一起进步 个人主页&#xff1a;LaNzikinh-CSDN博客 文章目录 前言一.引用二.内联函数三.类和对象总结 前言 之前讲c的命令空间和第一个程序的运行&#xff0c;继…

adb shell service命令与SurfaceFlinger调试

“ 在Android上有丰富的shell命令便于开发者用来调试程序&#xff0c;非常方便&#xff0c;本文简单说明下service命令的用法。” 01 基本用法 首先看一下使用说明&#xff0c;带上参数-h 或 -&#xff1f; $ adb shell service -h Usage: service [-h|-?]service listservi…

STM32 MDK Keil5软件调试功能使用(无需连接硬件)

MDK Keil5 在线仿真STM32&#xff08;无需连接硬件&#xff09; 首先点击工具栏的魔术棒配置一下&#xff1a;&#xff08;记得选择自己的STM32芯片类型&#xff09; 开启调试 使用逻辑分析仪查看IO输出 会打开这个界面&#xff0c;点击左边的setup按钮 会打开这个窗口&am…

交易量突破 3000 亿美元,去中心化衍生品协议 APX Finance 成最大的黑马?

“APX Finance 总交易量现已突破 3000 亿美元&#xff0c;已然成为链上衍生品赛道的主力军” 自 2021 年链上衍生品市场进入萌芽期以来&#xff0c;该板块始终保持着较高的市场增速&#xff0c;即便如此该领域仍旧存在极大的发展空间。一方面&#xff0c;衍生品板块交易量目前占…

【Kubernetes】k8s集群的污点、容忍、驱逐 以及排障思路

污点和容忍以及驱逐 一、污点&#xff08;Taint&#xff09; 污点介绍 节点亲和性&#xff0c;是Pod的一种属性&#xff08;偏好或硬性要求&#xff09;&#xff0c;它使Pod被吸引到一类特定的节点。Taint 则相反&#xff0c;它使节点能够排斥一类特定的 Pod。 Taint 和 Tol…

Docker 常用命令以及镜像选择

前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入工作的漩涡&#xff0c;忘记了停下脚步&#xff0c;感受周围的世界。让我们一起提醒自己&#xff0c;要适时放慢脚步…

PS系统教程12

画笔模式-绘画模式 相反组&#xff1a;理解一组即可 叠加、柔光重点理解&#xff0c;后面只是细微的差别差值-排除相当于胶卷留下的底片那样的效果。 正常和溶解的对比 正常-背后 效果&#xff1a;重叠的部分在就图层后面。 清楚与橡皮擦一样。 变暗 原理&#xff1a;比这个…

数学建模笔记

数学建模 定义角度 数学模型是针对参照某种事物系统的特征或数量依存关系&#xff0c;采用数学语言&#xff0c;概括地或近似地表述出的一种数学结构&#xff0c;这种数学结构是借助于数学符号刻画出来的某种系统的纯关系结构。从广义理解&#xff0c;数学模型包括数学中的各…

Linux系统之mv命令的基本使用

Linux系统之mv命令的基本使用 一、mv命令介绍1. mv命令简介2. mv命令的使用结果 二、mv命令的使用帮助1. 在命令行的帮助信息2. mv常用选项 三、mv命令的基本使用1. 创建源目录和目标目录2. 新建测试文件3. 将源目录文件复制到目标目录4. 将文件进行改名5. 将目录的所有文件转移…