当前位置: 首页 > news >正文

专做logo网站叫什么地方福田蒙派克10座黄牌报价

专做logo网站叫什么地方,福田蒙派克10座黄牌报价,更合公司网站建设,做网站月入1000#x1f30e; Linux信号详解 文章目录#xff1a; Linux信号详解 信号入门 技术应用角度的信号 信号及信号的产生       信号的概念       信号的处理方式 信号的产生方式         键盘产生信号         系统调用产生信号         软件… Linux信号详解 文章目录 Linux信号详解 信号入门 技术应用角度的信号 信号及信号的产生       信号的概念       信号的处理方式 信号的产生方式         键盘产生信号         系统调用产生信号         软件条件产生信号         异常产生信号 对信号产生方式的理解       键盘产生信号       异常信号的理解 信号入门 现实生活中的信号 你在网上买了很多件商品再等待不同商品快递的到来。但即便快递没有到来你也知道快递来临时你该怎么处理快递。也就是你能“识别快递” 当快递员到了你楼下你也收到快递到来的通知但是你正在打游戏需5min之后才能去取快递。那么在在这5min之内你并没有下去去取快递但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行可以理解成“在合适的时候去取”。 在收到通知再到你拿到快递期间是有一个时间窗口的在这段时间你并没有拿到快递但是你知道有一个快递已经来了。本质上是你“记住了有一个快递要去取” 当你时间合适顺利拿到快递之后就要开始处理快递了。而处理快递一般方式有三种1. 执行默认动作幸福的打开快递使用商品 2. 执行自定义动作快递是零食你要送给你你的女朋友 3. 忽略快递快递拿上来之后扔掉床头继续开一把游戏 快递到来的整个过程对你来讲是 异步 的你不能准确断定快递员什么时候给你打电话 技术应用角度的信号 用户输入命令在Shell下运行一个前台进程用户键盘输入 Ctrl C 2号信号则会产生一个硬件中断被OS获取解释成为信号发送给目标前台进程前台进程收到信号之后引起进程退出。 运行程序生成前台进程我们使用信号杀死前台进程 注意 Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个 可以放到后台运行这样Shell不必等待进程结束就可以接受新的命令启动新的进程。  Shell可以 同时运行 一个前台进程 和任意 多个后台进程只有 前台进程才能接到像 Ctrl-C 这种控制键产生的信号。 前台进程在运行过程中用户随时可能按下 Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是 异步(Asynchronous) 的。 信号及信号的产生 ✈️信号的概念 信号是进程之间事件异步通知的一种方式属于 软中断。 Linux中存在许多信号我们可以使用 kill -l 命令查看Linux中有哪些信号 Linux中有 62种信号前31种1~31信号被称为 标准信号每个信号都有特殊的含义及用途。后31种34~64信号被称为 实时信号可用于实时应用程序的拓展信号提供了更多的灵活性。注意中间并没有32和33号信号。 我们可以通过man手册来查询不同信号的含义 man 7 signal : 并且每个信号的编号都有自己的名字这些 名字 其实就 是 C 语言的 宏如果调用信号既可以通过信号的名称调用也可通过信号的编号调用。当然这么多的信号并不需要你全部记下来我们在运用的过程中就会知道哪些信号常用哪些不常用。 ✈️信号的处理方式 信号的 常见处理方式 有以下几种 忽略此信号。执行该信号的默认处理动作。提供一个信号处理函数要求内核在处理该信号时切换到用户态执行这个处理函数这种方式称为捕捉(Catch)一个信号。 我们以信号的方式来终止进程我们通过一下代码进行测试 #include iostream #include unistd.h #include sys/types.hint main() {while(true){std::cout Iam a proc, Im running now..., pid: getpid() std::endl;sleep(1);}return 0; }我们使用9号信号和2号信号杀死了进程这种发命令做出对应行为的方式 就是进程执行了信号的默认动作。好似阿熊在十字路口知道红灯停、绿灯行一样。 但是今天我们以 信号捕捉 的方式来处理发来的信号我们就需要用到 signal 接口 typedef void (*signhandler_t)(int); signhandler_t signal(int signum, sighandler_t handler);signum参数传入需要捕捉的信号名字或编号当进程收到与其相匹配的信号时则会调用第二个参数否则不会有任何动作。 handler参数handlder方法此方法为自定义方法当收到signum信号则不会执行该信号的默认动作变为执行该方法。 返回值返回前一个信号处理方法。 值得注意的是我们在设置信号捕捉时并不需要将此接口放入循环之中只需要调用该接口一次在整个程序中则一直循环有效。我们设置一个signal方法做测试 #include iostream #include unistd.h #include signal.h #include sys/types.hvoid handler(int signo)// 回调函数收到信号则执行handler方法 {std::cout get a sig, number is: signo std::endl; }int main() {signal(SIGINT, handler);// 设置信号捕捉while(true){std::cout Iam a proc, Im running now..., pid: getpid() std::endl;sleep(1);}return 0; }signal函数执行时并不会立刻对handler执行回调只有当收到对应的信号时才会执行回调。比如阿熊跟室友打赌输了接下来一周等红绿灯需要听室友的本来红灯停变为了红灯唱歌但是我们并不知道室友什么时候让阿熊唱歌。也就是说因为 信号是异步触发所以只有收到信号时才会执行回调。 信号的默认处理方式还剩下忽略信号也就是信号发送到进程但是进程对其不管不顾。在程序中使用捕捉的方式实现信号忽略那么signal第二个参数应该调用 SIG_IGNsignal ignore 在底层SIG_IGN 是将整形1强转为 __sighandler_t 类型于是就可以告诉OS进程运行时以忽略的方式将 signal 函数的第一个参数忽略 ✈️信号的产生方式 键盘产生信号 上面我们已经将以kill命令产生信号的方式介绍完了而信号的产生方式还有一种键盘产生信号我们在上面也说了使用 Ctrl-C 的方式可以终止进程这就是一种键盘产生信号的方式键盘产生信号的流程 键盘特定输入 —— OS解释为信号 —— 向目标进程发送信号 —— 进程收到信号 —— 进程做出响应 当我们把二号信号进行捕捉并且回调函数只对信号进行打印动作我们再使用 Ctrl-C 就杀不死该进程了 而键盘中并不只有 Ctrl-C 组合还有 Ctrl-\ 组合这里我使用的就是 Ctrl-\ 退出进程的其对应信号的 3号信号。 系统调用产生信号 除了键盘产生信号我们还可以使用系统调用产生信号Linux中存在 kill 接口 int kill(pid_t pid, int signo);功能给指定的进程发送指定的信号。 pid参数传入进程pid。 signo参数传入对进程发送的信号。 返回值发送成功返回0否则返回-1并设置错误码。 我们编写一段代码测试kill调用 #include iostream #include unistd.h #include signal.h #include cerrno #include cstring #include sys/types.hint main(int argc, char* argv[]) {if(argc ! 3)// 参数控制为三个{std::cout Usage: argv[0] -signumber pid std::endl;return 1;}// argv[0]: ./testSig 运行可执行程序// argv[1]: 发送的信号// argv[2]: 进程pidint signumber std::stoi(argv[1]);// argv[1]int pid std::stoi(argv[2]);// argv[2]int n kill(pid, signumber);if(n 0){std::cerr kill error, strerror(errno) std::endl;}return 0; }除了kill 系统调用之外Linux还提供了一个 raise 接口 int raise(int sig);功能传入信号给当前进程调用此接口的进程。 sig参数需要传入的信号。 返回值0表示成功非0为失败。 我们编写一段代码测试raise调用 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hint main(int argc, char* argv[]) {int cnt 0;while(true){std::cout cnt: cnt std::endl;sleep(1);if(cnt 5)// 5s 后退出进程{std::cout send 9 signal to caller std::endl;raise(9);}}return 0; }除了raise系统调用之外Linux还提供了一个 abort 接口 void abort(void)功能对自己发送指定的信号为6号信号 SIGABRT。 我们编写一段代码测试abort调用 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hint main(int argc, char* argv[]) {int cnt 0;while(true){std::cout cnt: cnt std::endl;sleep(1);if(cnt 5)// 5s 后abort进程{std::cout send 6 signal to caller std::endl;abort();}}return 0; }软件条件产生信号 我们曾经学过管道而管道四种特性有一种是 当没有读端时写端会被终止。管道不具备写的软件条件了所以触发了终止信号这种信号为 SIGPIPE13号信号。 除此之外由软件条件产生的信号还有 alarm 函数 和 SIGALRM14号信号 信号 unsigned int alarm(unsigned int seconds);功能用于试着进程闹钟指定时间以秒为单位后向调用它的进程发送 SIGALRM 信号。 seconds参数表示在多少秒后发送14号新号如果为0则任何未响应的 闹钟被取消。 返回值无符号整形表示上次设置的闹钟还剩余的秒数。之前未设置闹钟则返回0。 我们在代码上直观感受一下闹钟的相应 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hint main(int argc, char* argv[]) {// 设置一个闹钟alarm(1);int cnt 0;while(true){std::cout cnt: cnt std::endl;}return 0; }大概有3万七千次左右虽然我们云服务器配置不高但是3万7千次未免太少了。我们把打印信息注释掉并且设置一个全局变量让其在循环内一直做对14号信号再进行捕捉捕捉回调方法打印全局变量 这次运行居然有5亿多次累加至于为什么我们前面打印次数如此的少这里我给出两个原因 1.在Linux下一切皆文件前面对屏幕打印文字的行为本质上是对显示器文件进行疯狂打印。在前后对比下我们能直观的发现其实 IO很慢。   2.由于我们是使用了云服务器真正运行并不在本地运行我们向云服务器发送命令以及云服务器将信息从远端发到本地都是经过网络的。 闹钟在被设置的时候其默认动作只会响一次如果我们想要设置多个闹钟我们可以在回调handler方法里再加上n秒的闹钟这样第一次闹钟响了之后进程收到闹钟信号执行回调方法而main函数是被循环卡死的所以往后就每隔n秒响一次闹钟。 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hvoid handler(int signo)// 收到闹钟信号进行回调 { std::cout get a sign: signo std::endl;int n alarm(2);// exit(0); }int main(int argc, char* argv[]) {signal(SIGALRM, handler);// 设置一个闹钟alarm(4);int cnt 0;while(true){sleep(1);std::cout cnt: cnt std::endl;}return 0; }如果我们设定一个闹钟需要很久之后才会响应但是我在此期间发送14号信号提前对SIGALRM进行捕捉执行handler方法的回调返回值是什么呢 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hvoid handler(int signo)// 收到闹钟信号进行回调 { std::cout get a sign: signo std::endl;unsigned int n alarm(2);std::cout 闹钟剩余时间: n std::endl;// exit(0); }int main(int argc, char* argv[]) {signal(SIGALRM, handler);// 设置一个闹钟alarm(100);int cnt 0;while(true){sleep(1);std::cout cnt: cnt , pid is: getpid() std::endl;}return 0; }我们只对闹钟进行了一次kill信号我们第一个闹钟设置了100s而提示信息是每隔一秒打印一次算下来刚好过去5s打印出的返回值为95s而第二次回调的时候闹钟剩余时间就变为0了这也就证实了alarm接口返回值是上一次闹钟剩余时间。 接下来我来解释一下为什么闹钟也能作为软件条件我们知道alarm接口是系统调用接口也就是说设定闹钟实际上是在操作系统内部设定的。而操作系统中存在的闹钟定然不止一个所以OS一定要对这些闹钟做管理如何管理先描述再组织 根据以往经验闹钟一定是有自己的结构体结构体内有着必要的属性成员那么在结构体的属性成员当中就必定有闹钟的过期时间成员用来记录闹钟的过期时间 struct alarm {uint64_t expired_time;// 闹钟过期时间// ...其他属性字段 }而闹钟的过期时间实际上是一个时间戳一个线性增长的时间。那我们应该以什么样的结构组织起来这些闹钟呢经常看我博客的小伙伴第一反应很可能是链表。设置一个双链表按照闹钟过期时间来排序之后我只要找到第一个过期的闹钟那么在此之后必然全部都是过期闹钟。 虽然这种想法很好但是我们有更优解我在很早之前写过一篇博客堆与堆排序 而操作系统就是采用最小堆的方法组织闹钟结构以最小堆的堆顶一定是最近一次即将超时的闹钟。所以往后OS只需要查找堆顶元素过期了就释放掉再通过堆调整将次要过期的闹钟调整到堆顶。 异常产生信号 第五种信号的产生方式程序出了异常操作系统定然不会在放任这个问题进程不管会采取一定的措施OS为了能让程序员知道程序出了问题于是设置了一些常出现的异常信号当进程出现异常时OS将会对进程发送异常信号爆出异常缘由。 异常并不一定是由程序的语法、逻辑问题带来的可很有可能是外部设备出了问题所以异常又被分为 软件异常 和 硬件异常。 软件异常通常有除零错误或者溢出错误引起的。而硬件异常通常是有进程访问无效地址引起的一般有段错误等。具体情况具体分析我们先对除零错误进行模拟 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hint main(int argc, char* argv[]) {int a 10;a / 0;while(1) sleep(1);return 0; }除零错误会在Shell上爆出 Floating point exception 错误信息并且除零错误对应的信号是 SIGFPE8号信号。我们再来模拟一下野指针异常 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hint main(int argc, char* argv[]) {int* p nullptr;*p 50;return 0; }野指针异常通常会爆 Segmentation fault 错误想必学C/C的小伙伴对这种报错会经常见到而其对应的异常信号为 SIGSEGV11号信号。 硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。 对信号产生方式的理解 ✈️键盘产生信号 键盘产生数据毫无问题但是操作系统是如何对组合键做出特殊处理的OS怎么知道我使用Ctrl C 就是要发送2号信号给进程呢我们都知道操作系统向下管理软硬件资源那么键盘硬件资源当然也属于操作系统管理范畴。 所以我们从键盘输入组合键是由操作系统说的算的而你使用的组合键是被OS解释为了命令。输入方在与键盘解释方为操作系统也就是说键盘输入的到底是普通数据还是特殊命令是由键盘驱动和OS联合解释的。 这么看来操作系统只需要解释我们输入的信息即可但是对于OS来说用户输入的动作一定是异步的。而我们在日常使用键盘的时候操作系统似乎是优先处理的。这样对于操作系统的压力是不是有些大了要知道OS可不止需要监测键盘还有其他异步硬件网卡就是典型的例子。OS并不能保证何时会不会有信息从网络发来。 显然操作系统如果一直对这些异步发生的硬件进行监视的话会将操作系统的性能拉低而操作系统存在的意义就是向下对软硬件资源管理向上为用户提供良好服务。所以定然不会无时无刻监视这些硬件于是就有人提出了 硬件中断技术。 早在我们电脑开机的时候操作系统就给我们生成了一张 中断向量表 这张表提前注册对软硬件资源操作的方法。比如此表的二号下标的方法就是用来读取键盘输入的数据。而所谓的中断向量表实际上是一个 函数指针数组。那么其究竟是如何实现通过程序来访问硬件资源的呢 通过冯诺依曼结构我们知道CPU在数据层面只和内存级打交道。但是在每个CPU上都存在许多的针脚这些针脚是物理性的在主板上可以和各个硬件相连接包括键盘也是通过CPU的针脚连接的。每个针脚都有自己的编号。而未来我们在按键盘时通过针脚使 CPU触发硬件中断当然也没这么简单他们之间可能存在 8259可中断控制器这个我们目前不需要了解。 不管如何键盘和CPU可以通过针脚相互连接而用户在键盘上输入数据时发送高电平就会触发硬件中断此时CPU就可以检测到这个针脚有高电平从而识别到键盘。而这时CPU中的寄存器会将中断号针脚编号保存在寄存器内部至此硬件的动作就完成了 寄存器收到中断号后被操作系统检测到此时操作系统就会停下手头的工作。拿着这个中断号从中断向量表中查询中断号就是中断向量表的下标索引对应处理键盘资源的方法进而调用这个方法去收集键盘发来的数据了。于是就可以把从键盘输入的数据读取到内存当中了。严格意义上来说键盘文件也是文件OS会先将数据读入到键盘文件的缓冲区里。 读取到的键盘数据经过操作系统对字符的判定判定为数据则发送到当前进程打开的键盘文件缓冲区中而被判定为控制命令的组合键则会被解释为信号比如我输入了Ctrl C那么OS就会将其解释为2号信号而并非普通字符信息。这时这个信号就会发送给调用键盘文件的进程从而执行对应的动作。 那么操作系统如何解释控制命令实际上信号在到来时我们在处理更重要的事情暂时不能处理到来的信号所以我们一定需把信号保存到PCB中要知道信号可是有整整62种一个进程可能会存在多个信号所以OS定要对这些信号做管理如何管理先描述再组织 而这些信号则是由位图这结构描述组织的并且这个位图只需要32位比特位因为标准信号只有31种所以32位比特位完全够用。如果用户通过键盘对当前用户输入了Ctrl C则会被操作系统解释为2号信号通过位图将第对应的比特位由0置1即可完成OS对进程发送信号。也就是说操作系统向进程发送信号的本质是对进程PCB的位图进行写入操作! ✈️异常信号的理解 前面出现了 除零错误SIGFPE以及野指针错误SIGSEGV都属于异常产生的信号首先我们来分析除零错误。 计算错误 除零错误实际上也就是计算错误在硬件方面计算错误表现在CPU的寄存器上我们知道程序的计算都是在寄存器内完成的寄存器可以存贮少量数据而当计算发生错误CPU停止对进程的操作转而告诉操作系统当前处理的进程发生了计算错误。 在CPU中存在一个标志寄存器EFLAGS/RFLAGS标志寄存器其 用于检测有符号数运算是否发生了溢出。这个寄存器存在一个名为 OF(OverFlow) 的标志位。当发生溢出错误时OF被置为1否则被置为0。 操作系统收到CPU发来的信息发现进程不再被调度了于是操作系统就会检查EFLAGS/RFLAGS寄存器的溢出标记位OF从而检测出当前进程出了计算异常于是 OS就对当前进程发送向pcb内写入8号信号 当我们对除零错误的异常信号进行捕捉并且保持进程一直在运行状态 #include iostream #include unistd.h #include signal.h #include cerrno #include string #include cstring #include sys/types.hvoid handler(int signo) {std::cout get a sig: signo std::endl; }int main(int argc, char* argv[]) {signal(SIGFPE, handler);int a 10;int b 0;a a / b;while(true) sleep(1);return 0; }我们把异常信号的默认执行方式进行了捕捉从而执行我们的handler方法回调。而handler方法我们仅仅打印了一句话所以这个异常信号依旧存在。我们都知道在CPU中寄存器只有一套而 寄存器的数据可以有很多这些数据我们称为 进程的上下文数据。 但是当前进程被我们设置为一直在运行异常在进程中仍然存在这个时候OS又会向OF读取异常数据进而再一次的对当前进程发送8号信号这样不断的循环就导致了上图的结果。 野指针异常 野指针异常是因为非法访问地址而我们通过之前的学习我们知道野指针内的地址一定是虚拟地址而虚拟地址要映射到物理内存需要经过 由OS和CPU(MMU) 的 转化。而既然存在转化就一定存在转化成功或者失败我们来讨论一下转化失败的情况。 在CPU中还存在两个很重要的寄存器CR2 和 CR3 寄存器其中cr2寄存器 用于存储导致页表映射错误的虚拟地址。而cr3寄存器用于 存储页表的基地址指向当前页表。现代电脑上的 MMU单元 都是被集成的CPU上的其用于 虚拟到物理地址之间的转换。 当程序中发生了野指针错误比如对空地址解引用赋值。此时当CPU执行到该语句的时候会将指针内保存的虚拟地址由MMU和OS经过页表转化为物理地址但是在转化的时候页表中可能没有该虚拟地址的映射或者该映射的物理地址不可被写入无w权限。此时MMU就会转化失败于是就向cr2寄存器写入出错的虚拟地址cr2将虚拟地址保存。 当进程出现了野指针异常时当前进程就会停止调度OS就会来检查为何当前进程停止调度而CPU对cr2寄存器进行读取发现当前进程出现了野指针错误于是OS就对当前进程发送11号信号SIGSEGV从而终止进程 总结 所以产生信号不论是系统调用还是软件条件亦或者是键盘、异常产生的信号都是由操作系统同一发送的因为OS作为软硬件资源的管理者当进程出现异常时需要对进程做相应的处理这也就是为什么我们在windows下运行一些带有错误的程序时进程会直接终止。 今天的文章到此结束感谢您的观看如果对您有帮助的话还望给博主一个小小的三连呀~~
http://www.hkea.cn/news/14292823/

相关文章:

  • 营销型网站模板免费下载深圳龙岗淘宝网站建设公司有哪些
  • 建设自己网站的流程图东莞建站多少钱
  • 网站开发专业定制西安推广公司
  • 网站做优化公司建设网站的公司兴田德润怎么联系
  • 受欢迎的昆明网站建设镇江门户网
  • 常熟市住房和城乡建设部网站重庆建设工程信息网哪里可以查看二级建造师已解锁
  • 设计模板网站中国有没有开源社区
  • 上海网站建设公司2018年做网站赚钱
  • 一个网站备案两个域名吗长沙市网站建设
  • logo设计在线生成免费网站永久免费虚拟主机
  • 做网站公司不给源码wordpress怎么分段
  • 公司内网网站建设软件外包开发保密协议
  • 江苏网站建设方案cms内容管理系统是什么
  • 哪个网站可以学做包子汽车之家app下载最新版
  • 广告网站设计方案自建网站过程
  • 大庆建设集团网站全球4a广告公司排名
  • 网站公司建设个服务号多少钱开发网站做什么
  • 建设银行网站查询做网站的收获及感想
  • html5网站都有那个网站检测
  • 邯郸网站制作seo执行招聘
  • 废品网站怎么做久久建筑网碗扣式钢管脚手架安全技术规范
  • 期末作业制作网站宝山区网站建设
  • 网站开发设计的技术ip138查询域名查询
  • 怎么注册域名网站怎么查找网站的服务器
  • 免费企业网站建设要求互联网公司裁员
  • 营销网站型建设多少钱wordpress面打开404
  • 中企动力科技股份有限公司网站官网广告产品
  • 如何做网站平台网站制作九江
  • 网站建设运营要求515ppt模板网
  • 怎样增加网站收录量石家庄个人建站网站策划