LinuxC编程——进程
目录
- 一、概念
- 1.1 程序
- 1.2 进程
- 二、特点⭐⭐⭐
- 三、进程段
- 四、进程分类
- 五、进程状态
- 六、进程状态转换图
- 七、函数接口
- 1. 创建子进程
- 2. 回收进程资源
- 3. 退出进程
- 4. 获取进程号
- 八、守护进程
一、概念
进程和程序是密不可分的两组概念,相对比,便于理解。
1.1 程序
简单来说,程序即编译好的可执行文件
展开来说:
- 编译好的可执行文件
- 存放在磁盘上的指令和数据的有序集合(文件)
- 静态的,没有执行的概念
1.2 进程
程序一次执行过程,是动态的,包括创建、调度、执行以及消亡,它是一个独立的可调度的任务
展开来说:
- 进程是程序的一次执行过程。
- 进程是动态的,包含创建、调度、执行、消亡。
- 进程是执行一个程序分配资源的总称。
- 独立的可调度的任务
二、特点⭐⭐⭐
- 系统会为每一个进程分配0-4g的虚拟空间,其中0-3g(用户空间)是每个进程所独有的,3g-4g(内核空间)是所有进程共有的。
- CPU调度进程时会给进程分配时间片(几毫秒 ~ 十几毫秒),当时间片用完后,cpu再进行其他进程的调度,实现进程的轮转,从而实现多任务的操作。
三、进程段
Linux中的进程包含三个段:
- “数据段”存放的是全局变量、常数以及动态数据分配的数据空间(如malloc函数取得的空间)等。
- “正文段”存放的是程序中的代码
- “堆栈段”存放的是函数的返回地址、函数的参数以及程序中的局部变量
四、进程分类
- 交互进程:该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类进程会立刻响应,典型的交互式进程有:shell命令进程、文本编辑器等
- 批处理进程:该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。
- 守护进程:该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。
五、进程状态
- 运行态(TASK_RUNNING)R:指正在被CPU运行或者就绪的状态。这样的进程被成为runnning进程。
- 睡眠态(等待态):
- 可中断睡眠态(TASK_INTERRUPTIBLE)S:处于等待状态中的进程,一旦被该进程等待的资源被释放,那么该进程就会进入运行状态。
- 不可中断睡眠态(TASK_UNINTERRUPTIBLE)D:该状态的进程只能用wake_up()函数唤醒。
- 暂停态(TASK_STOPPED)T:当进程收到信号SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU时就会进入暂停状态。可向其发送SIGCONT信号让进程转换到可运行状态。
- 死亡态X:进程结束
- 僵尸态(TASK_ZOMBIE)Z:当进程已经终止运行,但还占用系统资源,要避免僵尸态的产生(例如:在父子进程中,子进程比父进程先结束,而父进程没有对子进程及时回收,释放子进程占用的资源,此时子进程将变成一个僵尸进程)。
六、进程状态转换图
进程创建后,进程进入就绪态,当CPU调度到此进程时进入运行态,当时间片用完时,此进程会进入就绪态,如果此进程正在执行一些IO操作(阻塞操作)会进入阻塞态,完成IO操作(阻塞结束)后又可进入就绪态,等待CPU的调度,当进程运行结束即进入结束态。
七、函数接口
1. 创建子进程
pid_t fork(void);
-
功能:创建子进程
-
参数:无
-
返回值
- 成功:在父进程中:返回子进程的进程号 >0;在子进程中:返回值为0
- 失败:-1并设置errno
-
特点⭐⭐⭐
- 子进程几乎拷贝了父进程的全部内容,包括:代码、数据、系统数据段中的pc值、栈中的数据、父进程中打开的文件等;但它们的PID、PPID是不同的。
- 父子进程有独立的地址空间,互不影响;当在相应的进程中改变全局变量、静态变量,都互不影响。
- 若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程。
- 若子进程先结束,父进程如果没有及时回收,子进程变成僵尸进程(要避免僵尸进程产生)
-
拓展:
- fork之前的代码被复制,但是不会重新执行一遍;fork之后的代码被复制,并且再被执行一遍。
- fork之后两个进程相互独立,子进程拷贝了父进程的所有代码,但内存空间独立
- fork之前打开文件,fork之后拿到的是同一个文件描述符,操作的是同一个文件指针。(而不同的进程打开相同的文件,操作的是不同的文件指针)
- fork函数创建父子进程后各自执行顺序不一定(vfork:先执行完子进程,再执行父进程)
-
例子:
#include <stdio.h>
#include <unistd.h>
// 若父进程先结束,子进程将变成孤儿进程 且被init进程收养,变成孤儿进程
// 若子进程先结束,父进程如果没与及时回收,子进程将变成僵尸进程
int main(int argc, char const *argv[])
{int a =0;pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){ // 运行子进程printf("child a:%d\n",a);while(1);}else{ // 运行父进程a=3;printf("parent a:%d\n",a);//while(1);}return 0;
}
2. 回收进程资源
- wait:pid_t wait(int *status);
- 功能:回收子进程资源(阻塞)
- 参数
- status:子进程退出状态,不接受子进程状态设为NULL
- 返回值
- 成功:回收的子进程的进程号
- 失败:-1
- waitpid:pid_t waitpid(pid_t pid, int *status, int options);
- 功能:回收子进程资源
- 参数:
- pid:
- status:子进程退出状态
- options:
- 0:阻塞
- WNOHANG:非阻塞
- pid:
- 返回值
- 正常:结束的子进程的进程号
- 当使用选项WNOHANG且没有子进程结束时:0
- 出错:-1
- 例
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{int a = 0;pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){printf("in child a=%d\n",a);// while(1);sleep(1);}else{a = 3;// wait(NULL); //阻塞回收所有子进程// waitpid(-1,NULL,0); //阻塞回收所有子进程waitpid(pid,NULL,0); // 阻塞回收pid进程// waitpid(pid,NULL,WNOHANG); //不阻塞回收进程号为pid的进程printf("in parent a = %d\n",a);// while(1);wait(NULL);printf("parent end...\n");}return 0;
}
3. 退出进程
- exit :void exit(int status);
- 功能:结束进程,刷新缓存
- 参数:退出的状态
- _exit:void _exit(int status);
- 功能:结束进程,不刷新缓存
- 参数:status是一个整型的参数,可以利用这个参数传递进程结束时的状态。
通常0表示正常结束;其他的数值表示出现了错误,进程非正常结束
注:exit与return的区别⭐⭐
- exit:函数,不管在子函数还是主函数,都可以结束进程(进程的退出)
- return:关键字,当子函数中有return时返回到函数调用位置,并不结束进程(函数的退出)
例子:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>void fun(int a, int b)
{printf("a+b=%d",a+b);// exit(0); // 结束进程,刷新缓存_exit(0); // 结束进程,不刷新缓存return;
}int main(int argc, char const *argv[])
{pid_t pid = fork();if(pid<0){perror("fork err");return -1;}else if(pid == 0){printf("in child\n");fun(3,4);sleep(1);}else{printf("in parent\n");// while(1);wait(NULL);printf("parent end...\n");}return 0;
}
运行结果:
exit:会刷新缓存
_exit:不会刷新缓存
4. 获取进程号
- getpid:pid_t getpid(void);
- 功能:获取当前进程的进程号
- getppid:pid_t getppid(void);
- 功能:获取当前进程的父进程号
例:
- 功能:获取当前进程的父进程号
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.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("childpid:%d ppid:%d pid:%d\n",getpid(),getppid(),pid);exit(0);}else{printf("parentpid:%d ppid:%d pid:%d\n",getpid(),getppid(),pid);wait(NULL);}return 0;
}
运行:
练习:通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest
- 方法一
这里先执行子进程来进行源文件后半部分的复制,然后执行父进程来进行源文件前半部分的复制
方法二:
这里先执行父进程来进行源文件前半部分的复制,后执行子进程来进行源文件后半部分的复制
//通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件
//的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{if (argc != 3){printf("Please input:%s <srcfile> <destfile>\n", argv[0]);return -1;}int src = open(argv[1], O_RDONLY);if (src < 0){perror("srcfile open err");return -1;}int dest = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0666);if (dest < 0){perror("destfile open err");return -1;}off_t half = lseek(src, 0, SEEK_END) / 2; // 文件长度的一半int flag = 0; // 控制下面父子进程执行顺序,让父进程先执行ssize_t s;char buf[32] = {0};pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) // 子进程 复制源文件后半部分{while (flag == 1) // 父进程已复制完毕,子进程可以执行{lseek(src, half, SEEK_SET);lseek(dest, half, SEEK_SET);while ((s = read(src, buf, 32)) != 0)write(dest, buf, s);}}else // 父进程 复制源文件前半部分(先执行){lseek(src, 0, SEEK_SET);lseek(dest, 0, SEEK_SET);int n = half;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}else{while ((s = read(src, buf, 32)) != 0){write(dest, buf, s);n = n - s;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}}}}close(src);close(dest);return 0;
}
//通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件
//的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{if (argc != 3){printf("Please input:%s <srcfile> <destfile>\n", argv[0]);return -1;}int src = open(argv[1], O_RDONLY);if (src < 0){perror("srcfile open err");return -1;}int dest = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0666);if (dest < 0){perror("destfile open err");return -1;}off_t half = lseek(src, 0, SEEK_END) / 2; // 文件长度的一半int flag = 0; // 控制下面父子进程执行顺序,让父进程先执行ssize_t s;char buf[32] = {0};pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) // 子进程 复制源文件后半部分{while (flag == 1) // 父进程已复制完毕,子进程可以执行{lseek(src, half, SEEK_SET);lseek(dest, half, SEEK_SET);while ((s = read(src, buf, 32)) != 0)write(dest, buf, s);}}else // 父进程 复制源文件前半部分(先执行){lseek(src, 0, SEEK_SET);lseek(dest, 0, SEEK_SET);int n = half;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}else{while ((s = read(src, buf, 32)) != 0){write(dest, buf, s);n = n - s;if (n < 32){read(src, buf, n);write(dest, buf, n);flag = 1;wait(NULL);}}}}close(src);close(dest);return 0;
}
八、守护进程
- 特点
守护进程是后台进程;生命周期比较长,从系统启动时开启,系统关闭时结束;它是脱离控制终端且周期执行的进程。 - 实现步骤
- 创建子进程,父进程退出
让子进程成为孤儿进程,成为后台进程。fork - 在子进程中创建新会话
让子进程成为会话组组长,为了让子进程脱离控制终端。setsid() - 改变运行路径为根目录。chdir
原因:提高权限,让运行路径不能被删除或卸载。chdir - 重设权限掩码。umask
目的:增大进程创建文件的权限,提高灵活性。umask - 关闭不必要的文件描述符
目的:关闭不必要的文件描述符。close
- 创建子进程,父进程退出
- 练习:创建一个守护进程,循环间隔1s向文件中写入一串字符“hello”
/*创建守护进程实现往日志文件中循环写入hello,间隔时间为1秒*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>int main(int argc, char const *argv[])
{//1.创建父子进程pid_t pid = fork();if(pid < 0){perror("fork err");return -1;}else if(pid == 0) //子进程进入{setsid(); //2.在子进程中创建新会话,让子进程成为会话组组长chdir("/"); //3.改变运行目录为根目录umask(0); //4.重设文件掩码close(0);//5.关闭文件描述符->0 1 2close(1);int fd = open("/tmp/c.log",O_WRONLY|O_CREAT|O_APPEND,0666);if(fd < 0){perror("open err");return -1;}}else{exit(0); //1.父进程退出}return 0;
}
相关文章:

LinuxC编程——进程
目录 一、概念1.1 程序1.2 进程 二、特点⭐⭐⭐三、进程段四、进程分类五、进程状态六、进程状态转换图七、函数接口1. 创建子进程2. 回收进程资源3. 退出进程4. 获取进程号 八、守护进程 一、概念 进程和程序是密不可分的两组概念,相对比,便于理解。 1.…...
深入理解设计模式-结构型之适配器
适配器模式(Adapter Pattern): 适配器模式用于将一个类的接口转换成另一个类的接口,以使两者能够一起工作。适配器模式通常用于处理已经存在的类,让它们能够与其他类协同工作,而不需要修改原始类的代码。&…...

桥梁结构健康监测系统,智能预警降低桥梁安全隐患
桥梁通常位于现代综合交通网络中的咽喉部位,对区域经济发展起着重要的推进作用,然而在为社会经济发展做出巨大贡献的同时,它们不可避免地会在荷载作用、环境侵蚀和自然灾害等影响下出现材料腐蚀劣化、结构损伤开裂、性能退化和功能失效等损伤…...

夏威夷等全球多地深陷「末日狂烧」,关键时刻 AI 监测能否跑赢野火?
内容一览:当地时间 8 月 8 日,美国夏威夷州突发野火,当地居民和游客不得不跳入太平洋中躲避火势。截至 8 月 17 日,这场野火已经造成110 人死亡,超过 1000人失踪。与此同时,美国、加拿大、法国等地也正遭遇…...

解决多模块内核心模块有接口打包成jar后被依赖并调用遇到的问题(springcloud集成ruoyi.quartz)
项目准备开发个新功能,刚好很喜欢ruoyi写的任务调度,因此想到了集成ruoyi.quartz模块 ,遇到了很多问题: 首先因为ruoyi.quartz模块依赖了ruoyi.common模块,因此第一步我需要把common模块一部分依赖项复制到了quartz模块内…...
【kubernetes系列】Kubernetes之Kubelet运行机制和状态更新机制
Kubelet运行机制 Kubelet是Kubernetes中的一个重要组件,在每个 Node 节点上都会启动 kubelet 服务。 该服务主要用于处理 Master 节点下发到本节点的任务,管理 Pod及Pod 中的容器。每个kubelet 进程会在 API Server 上注册节点自身信息,定期…...

(学习笔记-进程管理)怎么避免死锁?
死锁的概念 在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。 那…...
【golang】链表(List)
List实现了一个双向链表,而Element则代表了链表中元素的结构。 可以把自己生成的Element类型值传给链表吗? 首先来看List的四种方法。 MoveBefore方法和MoveAfter方法,它们分别用于把给定的元素移动到另一个元素的前面和后面。 MoveToFro…...
android平台的语音聊天助手源码
目录 1 android平台的语音聊天助手源码 1.1 //js处理工具类 1.1.1 openImage 1.2 LoadWebDetails android平台的语音聊天助手源码package com.shrimp.xiaoweirobot.net; import java.util.ArrayList;...
Python读取Word统计词频输出到Excel
1.安装依赖的包 "# 读取docx\n", "!pip install python-docx\n", "!pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-docx\n", "# 中英文分词\n", "!pip install jieba\n", "!pi…...
windows docker mysql8.0 挂载配置文件不生效的问题
原因 mysql 8.0 遇到sql_modeonly_full_group_by的问题,于是就自定义my.cnf 去掉only_full_group_by,修改my.cnf 文件后,进行映射启动 docker run 命令 docker run -p 3306:3306 --privilegedtrue --restartalways -d --name axsc-mysql -…...

openGauss学习笔记-42 openGauss 高级数据管理-触发器
文章目录 openGauss学习笔记-42 openGauss 高级数据管理-触发器42.1 语法格式42.2 参数说明42.3 示例 openGauss学习笔记-42 openGauss 高级数据管理-触发器 触发器会在指定的数据库事件发生时自动执行函数。 42.1 语法格式 创建触发器 CREATE TRIGGER trigger_name { BEFORE…...

Leetcode33 搜索旋转排序数组
题解: /*** 旋转排序数组可分为N1 N2两个部分,如:[4,5,6,7,1,2,3],N1为[4,5,6,7],N2为[1,2,3]** 必然满足以下两个条件:* 1. N1和N2都是分别递增的;* 2. N1中的所有元素大于N2中的所有元素;** …...

docker 第一章
目录 1.安装 docker 2.镜像、容器 3.总结 1.安装 docker 2.镜像、容器 3.总结 容器在 linux 上的本机运行,与其他容器共享主机的内核。它运行的是一个独立的进程,不占用其他任何可执行文件的内存,非常轻量级。...
注册中心 —— SpringCloud Netflix Eureka
Eureka 简介 Eureka 是一个基于 REST 的服务发现组件,SpringCloud 将它集成在其子项目 spring-cloud-netflix 中,以实现 SpringCloud 的服务注册与发现,同时提供了负载均衡、故障转移等能力,目前 Eureka2.0 已经不再维护…...

2023年国赛数学建模思路 - 案例:异常检测
文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…...

⛳ Java 反射
目录 ⛳ Java 反射🎨 一、反射概述**🎃 使用反射的前提条件: **🎲 类正常加载过程如下图:反射优缺点:🧸 Java反射机制提供的功能: **🥅 反射主要API** 🏭 二、反射的使用Ἲ…...
Android 13 像Settings一样开启关闭深色模式
一.背景 由于客户定制的Settings需要开启关闭深色模式,所以需要自己调用开启关闭深色模式 二.前提条件 首先应用肯定要是系统应用,并且导入framework.jar包,具体可以参考: Android 应用自动开启辅助(无障碍)功能并使用辅助(无障碍)功能_android 自动开启无障碍服务_龚礼鹏…...

微服务实战项目-学成在线-项目优化(redis缓存优化)
微服务实战项目-学成在线-项目优化(redis缓存优化) 1 优化需求 视频播放页面用户未登录也可以访问,当用户观看试学课程时需要请求服务端查询数据,接口如下: 1、根据课程id查询课程信息。 2、根据文件id查询视频信息。 这些接口在用户未认…...

IDEA 找不到项目 ‘org.springframework.boot:spring-boot-starter-parent:3.1.2‘
找不到项目 ‘org.springframework.boot:spring-boot-starter-parent:2.6.7’ 这个问题主要是因为ide的缓存导致的,我们直接清理缓存并重启ide 重启之后ide会对pom文件进行编排索引完成之后问题就没有了...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...