【linux】进程信号——信号的产生
进程信号
- 一、信号概念
- 1.1 信号理解
- 二、产生信号
- 2.1 通过键盘产生信号
- 2.2 捕捉信号自定义signal
- 2.3 系统调用接口产生信号
- 2.3.1 向任意进程发送任意信号kill
- 2.3.2 给自己发送任意信号raise
- 2.3.3 给自己发送指定信号abort
- 2.3.4 理解
- 2.4 硬件异常产生信号
- 2.4.1 除0异常
- 2.4.2 野指针异常
- 2.4.3 总结
- 2.5 软件条件产生信号
- 2.5.1 定时器软件条件alarm
- 2.5.2 alarm的深层理解
- 2.6 核心转储Core Dump
一、信号概念
首先要知道查看信号的指令:kill -l
通过观察发现没有0和32和33号信号,只有1 ~ 31, 34 ~ 64的信号。我们把
【1 ~ 31】叫做普通信号
【34 ~ 64】叫做实时信号
1.1 信号理解
在日常生活中有很多的信号,例如红路灯、裁判哨声、闹钟,这些都是给我们人类看的,当这些场景触发的时候,我们人类立马就知道要做什么,并且产生行动。
而我们为什么能识别这些信号呢?
我们对特定事件的反应,是被教育的结果,本质是我们记住了。
还有一种情况:当信号传来的时候我们可能正在做更重要的事情,所以不一定会立马处理信号,此时信号的产生和我们正在做的事情称为异步。
我们把信号传递过来到处理之前的这段时间称为时间窗口。在时间窗口我们必须得记住这个信号。
在我们处理信号的时候,我们可以有不同的处理方式,比方说我们早上听到闹钟响起,会直接起床,这里叫做默认动作,而听到闹钟后先做十个俯卧撑再起床,这叫做自定义动作,当然我们也可以不理会闹钟,这叫做忽略动作。
把概念迁移到进程中:
1️⃣ 进程能认识信号并产生动作是因为程序员编码完成的。
2️⃣ 当进程收到信号,进程可能在执行更重要的代码,所以信号不一定被立即处理。 所以进程要有对信号的保存能力。
3️⃣ 进程在处理信号的时候,一般有三种动作:默认、自定义、忽略,有个专业名词叫:信号被捕捉。
那么信号是怎么被捕捉的呢?
信号发给进程,而进程需要保存到PCB中,那么如何保存呢?
是否收到信号具有原子性,只有两太,而我们知道普通信号是1 ~ 31,所以我们可以在PCB中创建一个unsigned int的变量,有32个比特位,刚好用这些比特位来标记接收的信号。比特位的位置代表信号的编号。0表示没有,1表示有。
所以发送信号的本质:修改PCB中的信号位图。
而只有操作系统才能修改PCB,发信号本质就是给操作系统发信号,那么操作系统就必须要提供发送信号、处理信号的相关调用接口,我们以前的kill指令就是调用了底层接口。
二、产生信号
2.1 通过键盘产生信号
ctrl + c
:是一个组合键,OS将它解释成3号信号(SIGQUIT)
我们知道每个信号有三种处理动作,那么怎么查看信号的默认动作是什么呢?
ctrl + \
:是一个组合键,OS将它解释成2号信号(SIGINT)
指令:man 7 signal
可以看到二号信号的动作是:Term(终止),描述是:Interrupt from keyboard(从键盘中断)
2.2 捕捉信号自定义signal
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);RETURN VALUE
signal() returns the previous value of the signal handler, or SIG_ERR on error.
In the event of an error, errno is set to indicate thecause.
参数说明:
signum
:指定的信号。
handler
:设置自定义动作,就是一个回调函数,函数内我们可以自定义我们想要的动作。
void handler(int sig)
{std::cout << "进程捕捉到信号,编号是:" << sig << std::endl;
}int main()
{signal(2, handler);while(true){std::cout << "in service: " << getpid() << std::endl;sleep(1);}return 0;
}
这里要注意是signal函数的调用,不是handler的调用。这个函数仅仅是对2号信号的捕捉,并不代表被调用了。只有收到对应信号才会被调用。
可以看到发送2号信号并不能导致进程被终止了。
这里有个问题:如果我们对所有的信号都进行了信号捕捉,那我们是不是就写了一个不会被异常终止或者用户杀掉的进程呢?我们通过代码来验证一下!
void Catchsig(int sig)
{std::cout << "捕捉到了一个信号: " << sig << " pid: " << getpid() << std::endl;
}int main()
{for(int i = 1; i <= 31; ++i)signal(i, Catchsig);while(1) sleep(1);return 0;
}
操作系统的设计者也考虑到了上述的情况,所以就让 9 号信号无法被捕捉,9 号信号是管理员信号。
2.3 系统调用接口产生信号
2.3.1 向任意进程发送任意信号kill
#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);RETURN VALUE
On success (at least one signal was sent), zero is returned.
On error, -1 is returned, and errno is set appropriately.
参数说明:
pid
:目标进程的pid。
sig
:向目标进程发送指定信号。
所以我们可以自己写一个kill的进程。
// mykill.cc
void Usage(const std::string& proc)
{std::cout << "\nerror, format: " << proc << " pid sig" << std::endl;
}int main(int argc, char* argv[])
{if(argc != 3){Usage(argv[0]);exit(1);}pid_t pid = atoi(argv[1]);int sig = atoi(argv[2]);kill(pid, sig);return 0;
}
再写一个永远运行的进程,让mykill进程来杀死它。
// myproc.cc
int main()
{while(true){std::cout << "please kill me, my pid: " << getpid() << std::endl;sleep(1);}return 0;
}
2.3.2 给自己发送任意信号raise
#include <signal.h>int raise(int sig);
RETURN VALUE
raise() returns 0 on success, and nonzero for failure.
sig就是发送的信号。
int main(int argc, char* argv[])
{int cnt = 0;while(++cnt < 10){std::cout << "cnt: " << cnt << std::endl;sleep(1);if(cnt == 5){raise(9);}}return 0;
}
其实这里raise也可以写成:kill(getpid(), 9)
2.3.3 给自己发送指定信号abort
#include <stdlib.h>void abort(void);
int main(int argc, char* argv[])
{int cnt = 0;while(++cnt < 10){std::cout << "cnt: " << cnt << std::endl;sleep(1);if(cnt == 5){abort();}}return 0;
}
而发送的指定信号就是6号(SIGABRT)。
所以这里abort也可以自己用kill封装:kill(getpid(), 6)
2.3.4 理解
我们可以看到进程收到的大部分信号,默认处理动作都是终止进程。
信号的不同代表了不同的事件,但是它们的处理动作可以一样。
2.4 硬件异常产生信号
2.4.1 除0异常
信号的产生不一定需要用户手动发送。
int main(int argc, char* argv[])
{while(true){std::cout << "in service" << std::endl;sleep(1);int a = 1;a /= 0;}return 0;
}
这里为什么/0
会导致进程终止呢?
因为进程会收到来自操作系统的8号信号(SIGFPE)。
我们可以用前面学的捕捉信号进行验证:
void handler(int sig)
{std::cout << "捕获到信号:" << sig << std::endl;sleep(1);
}int main(int argc, char* argv[])
{signal(8, handler);while(true){std::cout << "in service" << std::endl;sleep(1);int a = 1;a /= 0;}return 0;
}
这次我们把/0
放到循环前
可以看到这里还是循环打印,好像一直在调用捕获函数。
这里就要先知道操作系统是如何得知要给进程发送八号信号的呢?(怎么知道的/0
)
这里
1/0
会被放进CPU中的寄存器中,0相当于无穷小的数字,这样就会导致CPU的状态寄存器中的溢出标记由0变为1。这样就发生了CPU的运算异常,操作系统就会知道(操作系统是软硬件的管理者),然后向目标进程发送8号信号。而收到信号进程不一定退出,没有退出说明还会被继续调度。而寄存器的内容属于当前进程上下文信息,但是进程没有能力把状态标识符置为0,所以进程切换的时候就有无数次的状态寄存器被保存和恢复(上下文信息),每次恢复就会发送信号。导致捕获函数一直被调度。
2.4.2 野指针异常
int main(int argc, char* argv[])
{while(true){std::cout << "in service" << std::endl;sleep(1);int *ptr = nullptr;*ptr = 2;}return 0;
}
这里为什么空指针会导致进程终止呢?
因为进程会收到来自操作系统的11号信号(SIGSEGV)。
利用signal函数证明:
void handler(int sig)
{std::cout << "捕获到信号:" << sig << std::endl;sleep(1);
}int main(int argc, char* argv[])
{signal(11, handler);while(true){std::cout << "in service" << std::endl;sleep(1);int *ptr = nullptr;*ptr = 2;}return 0;
}
那么操作系统是如何知道发生了野指针情况呢?
我们知道指针本质上是个虚拟地址,而我们知道虚拟地址需要转化成物理地址,通过页表+MMU,MMU是集成在CPU中的硬件,通过访问通过页表的内容形成物理地址,再访问物理地址。而我们解引用空指针,MMU就会发生异常,然后被操作系统得知,然后发送信号给进程。
2.4.3 总结
大部分信号会导致进程退出,我们需要捕获这个异常,因为异常的不同代表不同的原因导致的,进而让我们能够追溯原因,让我们能够反向定位问题。比如说我们收到的信号是段错误,我们就会想到可能是野指针,收到浮点数溢出报错就会想到可能是除0错误。
2.5 软件条件产生信号
我们以前学过管道:【linux】进程间通信——管道通信
当两个进程正在利用管道进行读写,此时把读端关闭,操作系统就会终止掉写进程(发送SIGPIPE信号)。这种情况称为软件条件产生信号。
2.5.1 定时器软件条件alarm
#include <unistd.h>unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号(14), 该信号的默认处理动作是终止当前进程。
int main(int argc, char* argv[])
{alarm(1);int cnt = 0;while(true){std::cout << cnt++ << std::endl;}return 0;
}
这个进程的目的就是统计1s
的时间内计算机能将数据叠加多少次。
而如果我们这么写:
int cnt = 0;void handler(int sig)
{std::cout << "捕获到信号:" << sig << std::endl;std::cout << "cnt: " << cnt << std::endl;
}int main(int argc, char* argv[])
{signal(14, handler);alarm(1);while(true){++cnt;}return 0;
}
从这里就可以看到IO跟不IO的效率差距相当大。
而只打印了一次说明是收到了一个SIGALRM信号,闹钟响过一次就不再响了。
那如果我们想让它一直打印呢?
相当于在handler内部又要调用handler。这样就类似于sleep(1)
unsigned int alarm(unsigned int seconds);
当然alarm也可能提前响起。比方说有可能手动发送SIGALRM,他就会返回剩余多少时间。当我们把seconds设置为0,表示取消闹钟。
2.5.2 alarm的深层理解
我们知道每个进程都可能通过alarm接口设置闹钟,所以可能会存在很多闹钟,那么操作系统一定要管理起来它们。
先用一个结构体描述每个闹钟,其中包含各种属性:闹钟还有多久结束(时间戳)、闹钟是一次性的还是周期性的、闹钟跟哪个进程相关、链接下一个闹钟的指针…… 然后我们可以用数据结构把这些数据连接起来。
接下来操作系统会周期性的检查这些闹钟,当前时间戳和结构体中的时间戳进行比较,如果超过了,说明超时了,操作系统就会发送SIGALRM给该进程。
为了方便检查是否超时,可以利用堆结构来管理。
2.6 核心转储Core Dump
核心转储:
当进程出现异常的时候,我们可以将该进程在对应时刻的内容数据保存到磁盘上,文件名通常是 core。
这里的Term和Core都表示进程退出,Trem表示正常结束,操作系统不会做额外的工作,如果是Core退出,我们暂时看不到明显的现象,如果想要看到,我们可以打开一个选项:ulimit -a
(可以看到操作系统给用户所设置的资源上限)
可以看到第一行core file size的大小为0,因为云服务器默认关闭了core file
这个选项。
如果我们想修改我们就可以用后边的参数进行修改(-c)。ulimit -c
打开了以后我们继续解引用空指针:
可以发现比以前多了一点内容。在查看当前目录:
多了一个core文件
我们把core dumped叫做核心转储,core文件后面的数字就是问题进程的pid。
那么为什么要有核心转储?
我们需要知道程序为什么崩溃,在哪崩溃?而核心转储就是为了支持我们进行调试。
那么如何调试呢?
第一步先编译的时候带上-g
选项
第二步使用gdb调试
第三步直接输入core-file core.17633
从结果可以看出代码终止的原因是收到了11号信号,引发了段错误。在mykill.cc的17行。
我们把这种处理错误的方法叫做事后调试
总结一下:当程序出现异常,我们先确定是几号信号,然后man 7 signal查看是core还是Trem,如果是core,直接打开核心转储,然后gdb调试直接定位错误。
相关文章:
【linux】进程信号——信号的产生
进程信号一、信号概念1.1 信号理解二、产生信号2.1 通过键盘产生信号2.2 捕捉信号自定义signal2.3 系统调用接口产生信号2.3.1 向任意进程发送任意信号kill2.3.2 给自己发送任意信号raise2.3.3 给自己发送指定信号abort2.3.4 理解2.4 硬件异常产生信号2.4.1 除0异常2.4.2 野指针…...
部署OpenStack
部署 1. 环境配置 配置主机名 使用CRT软件连接controller节点和compute节点,用户名默认为root,密码默认为000000。连接上之后,使用linux命令修改节点主机名。 [rootcontroller ~]# hostnamectl set-hostname controller [rootcontroller …...
Java 运算符与类型转化
Java 运算符与类型转化 1 算术运算符 Java中的算术运算符主要有(加)、-(减)、*(乘)、/(除)、%(求余),它们都是二元运算符。 2 自增和自减运算…...
《C++ Primer Plus》第18章:探讨 C++ 新标准(2)
移动语义和右值引用 现在介绍本书前面未讨论的主题。C11 支持移动语义,这就提出了一些问题:为何需要移动语义?什么是移动语义?C11 如何支持它?下面首先讨论第一个问题。 为何需要移动语义 先来看 C11 之前的复制过程…...
QML定时器
QML使用Timer使用定时器 Timer 计时器可用于触发操作一次,或以给定的间隔重复触发。 常用属性: interval 设置触发器之间的间隔(以毫秒为单位)。 默认间隔为 1000 毫秒。 repeat 设置重复,为真,则以指定的…...
第三章 opengl之纹理
OpenGL纹理纹理环绕方式纹理过滤多级渐远纹理加载和创建纹理stb_image.h生成纹理纹理的应用纹理单元纹理 用stb_image.h库,原先用SOIL库也可以实现。 可以为每个顶点添加颜色来增加图形的细节。但是想得到一个真实的图形,需要足够多的顶点,…...
【Flink】FlinkSQL中执行计划以及如何用代码看执行计划
FilnkSQL怎么查询优化 Apache Flink 使用并扩展了 Apache Calcite 来执行复杂的查询优化。 这包括一系列基于规则和成本的优化,例如: • 基于 Apache Calcite 的子查询解相关 • 投影剪裁 • 分区剪裁 • 过滤器下推 • 子计划消除重复数据以避免重复计算 • 特殊子查询重写,…...
从业者必读,一篇文章轻松掌握DevOps核心概念和最佳技能实践!
文章目录前言一. DevOps的定义及由来二. DevOps的价值三. devops工具有哪些3.1 devops工程师的硬实力3.2 devops工程师的软实力总结前言 大家好,又见面了,我是沐风晓月,本文是对DevOps的总结,一篇文章告诉你什么是DevOps. 对很多…...
2023爱分析·一体化HR SaaS市场厂商评估报告:北森
目录 1.研究范围定义 2. 一体化HR SaaS市场分析 3.厂商评估:北森 4.入选证书 1.研究范围定义 研究范围 伴随数字化转型走向深入,企业人力资源数字化也进入快速发展阶段,人力资源的价值也得到了重新审视和定义。政策层面,《…...
JAVA练习67-二叉树的中序遍历
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-二叉树的中序遍历 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 3月3日练习…...
【JeecgBoot-Vue3】第1节 源码下载和环境安装与启动
目录 一. 资料 1. 源码下载 2. 官网启动文档 二、 前端开发环境安装 2.1 开发工具 2.2 前后端代码下载 2.3 前端启动 Step 1:安装nodejs npm Step 2:配置国内镜像(这里选阿里) Step 3:安装yarn Step 4&…...
WebAPI
WebAPI知识详解day11.Web API 基本认知作用和分类什么是DOM?DOM树的概念DOM对象2.获取DOM对象通过css选择器获取dom对象通过其他方法获取dom3.设置/修改DOM元素内容方法1. document.write() 方法方法2. 对象.innerText 属性方法3. 对象.innerHTML4.设置/修改DOM元素…...
Shell命令——date的用法
date命令可以用来显示或设定系统的日期与时间。 一、显示系统的日期与时间 (1)如果date命令后面不加任何参数,则会按照固定的格式显示时间信息: 星期几 月份 日 时:分:秒 时区 年xjhubuntu:~/iot/tmp$ date Fri Mar 3 16:56:4…...
XSS跨站脚本
XSS跨站脚本XSS简介XSS验证XSS危害XSS简介 XSS被称为跨站脚本攻击(Cross-site scripting),由于和CSS(Cascading Style Sheets)重名,所以改为XSS。XSS主要基于javascript语言完成恶意的攻击行为,因为javascript可以非常灵活的操作html、css和…...
【强烈建议收藏:MySQL面试必问系列之慢SQL优化专题】
一.知识回顾 学习本篇文章之前呢,我们可以先看一下【强烈建议收藏:MySQL面试必问系列之SQL语句执行专题】,看完这篇文章再来学习本篇文章可谓是如虎添翼。好的,那我们也不讲太多的废话,直接开始。 二.如何做慢SQL查询优化呢&…...
windows,liunx,java实现apk解压,去签名、重新签名,重新打包apk
背景:由于项目需要,需要将apk包加入服务端返回的静态资源文件到apk中,形成离线apk包供下载安装。经过调查研究,决定使用apktool实现。关于apktool的资料可以参考 https://blog.csdn.net/quantum7/article/details/124060620 htt…...
【Linux】进程信号
🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉信号入门&…...
SpringBoot 集成Junit单元测试
学习文章: https://www.cnblogs.com/ysocean/p/6889906.html 开发工具: IDEA 2022.1.4 目录 目录 1. 概述 2. 实现步骤 2.1 maven导入依赖 2.2 随意代码演示(不推荐) 2.3 规范代码演示(推荐) 3. Junit相关其他注解 4. 注意事项 5. 结语 1. 概述 接触到Junit,…...
Android开发之简单控件
文章目录一 文本显示1.1 文本设置的两种方式1.2 常见字号单位类型2.2 设置文本的颜色三 视图基础3.1 设置视图的宽高3.2 设置视图的间距3.3 设置视图的对齐方式四常用布局4.1 线性布局LinearLayout4.2 相对布局RelativeLayout4.3 网格布局GridLayout4.4 滚动视图ScrollView五 按…...
树状数组讲解
树状数组 文章目录树状数组引入例题AcWing241.楼兰图腾思路代码AcWing 242. 一个简单的整数问题思路代码AcWing 244. 谜一样的牛思路代码总结引入 树状数组主要维护的是这样一个数据结构: tr[x]表示以x为终点的长度为lowbit(x)的前缀和、最大值、最小值、最大公约数…...
每个Android开发都应需知的性能指标~
无论你是发布一个新的 Android 应用,还是希望提高现有应用的性能,你都可以使用 Android 应用性能指标来帮助你。 在这篇文章中,我将解释什么是 Android 应用性能指标,并列出8个需要考虑跟踪的维度和建议的基线。 什么是 Android…...
MSYS2安装
最近在学习windows上编译FFmpeg,需要用到msys2,在此记录一下安装和配置过程。 点击如下链接,下载安装包: Index of /msys2/distrib/x86_64/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 我下载的是:ms…...
3/3考试总结
时间安排 7:30–7:50 看题,怎么感觉三道构造,T3 貌似有网络流背景。 7:50–8:30 T1,有一些简单的性质,缩减两端点后枚举一下翻转的区间就可以了。然后花了一点时间写 spj 调试。 8:30–10:20 T2,比较纯粹的构造题。有网络流做法,…...
Spark Streaming DStream转换
DStream上的操作与RDD的类似,分为Transformations(转换)和Output Operations(输出)两种,此外转换操作中还有一些比较特殊的算子,如:updateStateByKey()、transform()以及各种Window相…...
水果商城,可运行
文章目录项目介绍一、技术栈二、本项目分为前后台,有管理员与用户两种角色;1、管理员角色包含以下功能:2、用户角色包含以下功能:三、用户功能页面展示四、管理员功能页面展示五、部分代码展示六、获取整套项目源码项目介绍 一、…...
LiveGBS国标GB/T28181国标视频流媒体平台-功能报警订阅配置报警预案告警截图及录像
LiveGBS国标GB/T28181国标视频流媒体平台-功能报警订阅配置报警预案告警截图及录像1、报警信息1.1、报警查询1.2、配置开启报警订阅1.2.1、国标设备编辑1.2.2、选择开启报警订阅1.3、配置摄像头报警1.3.1、配置摄像头报警通道ID1.3.2、配置摄像头开启侦测1.3.3、尝试触发摄像头…...
软件测试---测试分类
一 : 按测试对象划分 1.1 可靠性测试 可靠性(Availability)即可用性,是指系统正常运行的能力或者程度,一般用正常向用户提供软件服务的时间占总时间的百分比表示。 1.2 容错性测试 行李箱 , 四个轮子 , 坏了一个 , 说明这个容错…...
剑指 Offer II 015. 字符串中的所有变位词
题目链接 剑指 Offer II 015. 字符串中的所有变位词 mid 题目描述 给定两个字符串 s和 p,找到 s中所有 p的 变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 变位词 指字母相同,但排列不同的字符串。 示例 1: 输…...
【SpringCloud】SpringCloud详细教程之微服务比较
目录前言一.什么是微服务?为什么要使用微服务二.微服务对比三.企业开发场景前言 我会通过实际代码来给展示每个组件的用法 一.什么是微服务?为什么要使用微服务 分布式,把一个项目拆分成多个模块,每一个模块相当于一个服务。 微…...
二.项目使用vue-router,引入ant-design-vue的UI框架,引入less
根据前文《使用Vue脚手架工具搭建vue项目》搭建好脚手架后使用 1.vue-router 2.引入UI框架ant design vue 3.引入less 1.vue-router vue-router分为两种模式(默认为hash模式): hash history hash: 特征: 1.hash会在浏览器路径里带#号&#…...
好多公司为啥只做网站 不考虑推广/个人主页网页设计模板
一、参数说明 登陆微信开放平台(注意是开放平台,不是公众平台);https://open.weixin.qq.com 做app首先需要在微信开放平台后台创建应用,第二步勾选ios和Android应用平台,其中Android应用需要填写应用签名、…...
怎么做教育类型的网站/seo优化培训班
一、“平面设计”的内涵 • 所谓“平面设计”,指的是在平面空间上的设计活动,其设计的内容主要是在二维空间中各个元素的设计和这些元素组合的布局设计,其中包括字体设计、版面设计、插图、摄影的采用,而所有这些内容的核心在于传…...
wordpress 默认端口/网页设计网站
static作用(修饰函数、局部变量、全局变量)在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条。 (1)先来介绍它的第一条也是最重要的一条:隐藏。 当我们同时编译多个文件时&a…...
四川通信建设工程有限公司网站/百度的广告推广需要多少费用
今天做了一个图表页面,效果图如下: 上图红框中的部分,是指的table表格中,鼠标移入某行后,出现的背景颜色。默认的背景颜色是一种灰色。 鼠标移入后的行背景颜色修改 通过css即可实现: .el-table--enabl…...
网站分页用什么设置/申请一个网站需要多少钱
hongkong转载于:https://www.cnblogs.com/wszme/p/9678734.html...
精品建设课程网站/短网址链接生成
Win8 Metro(C#)数字图像处理--2.59 P分位法图像二值化 原文:Win8 Metro(C#)数字图像处理--2.59 P分位法图像二值化[函数名称] P分位法图像二值化 [算法说明] 所谓P分位法图像分割,就是在知道图像中目标所占的比率Ratio时,循环不…...