信号-3-信号处理

server/2024/11/18 13:23:59/

main

信号捕捉的操作

sigaction

struct sigaction

OS不允许信号处理方法进行嵌套:某一个信号正在被处理时,OS会自动block改信号,之后会自动恢复

同理,sigaction.sa_mask 为捕捉指定信号后临时屏蔽的表

pending什么时候清零:调用handler前就清零,否则不能判断handler期间是否收到指定signal

可重入函数

问题:

一个函数,被两个以上的执行流进入了--重入

出问题了--不可重入函数

没出问题--可重入函数

如何判断可/不可重入

有全部资源:不可重入

全是局部:可

大部分都不可

函数名后带_r:可

volatile

关键字(异变关键字)

防止优化,保证每次从内存读取改变量,保证内存可见性。

因为常用与修饰容易改变的变量,所以叫做异变关键字

// 易变关键字
volatile int flag = 0;void change(int signo) // 信号捕捉的执行流
{(void)signo;flag = 1;printf("change flag 0->1, getpid: %d\n", getpid());
}int main()
{printf("I am main process, pid is : %d\n", getpid());signal(2, change);while(!flag); // 主执行流--- flag我们没有做任何修改!printf("我是正常退出的!\n");
}

0没有优化

1-3优化

为什么优化后不会退出

register 直接把一变量放到寄存器,不用每次从内存读取

信号流改变flag,只改变内存flag,对寄存器没有影响

所有的关键字都是给编译器看的,

SIGCHLD

子进程退出时,会给父进程发送SIGCHLD信号

这样,父进程不必阻塞来wait子进程或者使用WNOHANG频繁轮询子进程

对于SIGCHLD,默认的handler方法为ignore

同理

SIGSTP

SIGTSTP

缺点

多进程时不行

解决:循环回收

#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>// void handler(int signo)
// {
//     std::cout << "get a sig: " << signo << " I am : " << getpid() << std::endl;
//     while (true)
//     {
//         pid_t rid = ::waitpid(-1, nullptr, WNOHANG);
//         if (rid > 0)
//         {
//             std::cout << "子进程退出了,回收成功,child id: " << rid << std::endl;
//         }
//         else if(rid == 0)
//         {
//             std::cout << "退出的子进程已经被全部回收了" << std::endl;
//             break;
//         }
//         else
//         {
//             std::cout << "wait error" << std::endl;
//             break;
//         }
//     }
// }// 1. 验证子进程退出,给父进程发送SIGCHLD
// 2. 我们可不可以基于信号进行子进程回收呢?
int main()
{// signal(SIGCHLD, handler);// Linux下,将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉::signal(SIGCHLD, SIG_IGN);// 问题1: 1个子进程,10个呢?// 问题2: 10个子进程,6个退出了!for (int i = 0; i < 10; i++){if (fork() == 0){sleep(5);std::cout << "子进程退出" << std::endl;// 子进程exit(0);}}while (true){sleep(1);}return 0;
}

问题:只退出一半,会阻塞

解决:WNOHANG

对 SIGCHLD设置为SIGIGN会自动回收子进程,不会产生僵尸进程,用于不关心子进程返回结果

系统默认对SIGCHLD执行SIG_IGN,为什么我们还要再次手动设置其为SIG_IGN:

不能保证类UNIX,Windows与linux对SIGCHILD处理方式相同

code

// #include <iostream>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 易变关键字
volatile int flag = 0;void change(int signo) // 信号捕捉的执行流
{(void)signo;flag = 1;printf("change flag 0->1, getpid: %d\n", getpid());
}int main()
{printf("I am main process, pid is : %d\n", getpid());signal(2, change);while(!flag); // 主执行流--- flag我们没有做任何修改!printf("我是正常退出的!\n");
}// // printBLocklist
// void PirintBLock()
// {
//     sigset_t set, oset;
//     sigemptyset(&set);
//     sigemptyset(&oset);//     sigprocmask(SIG_BLOCK, &set, &oset);
//     std::cout << "block: ";
//     for (int signo = 31; signo > 0; signo--)
//     {
//         if (sigismember(&oset, signo))
//         {
//             std::cout << 1;
//         }
//         else
//         {
//             std::cout << 0;
//         }
//     }
//     std::cout << std::endl;
// }// void PrintPending()
// {
//     sigset_t pending;
//     ::sigpending(&pending);//     std::cout << "Pending: ";
//     for (int signo = 31; signo > 0; signo--)
//     {
//         if (sigismember(&pending, signo))
//         {
//             std::cout << 1;
//         }
//         else
//         {
//             std::cout << 0;
//         }
//     }
//     std::cout << std::endl;
// }// void handler(int signo)
// {
//     static int cnt = 0;
//     cnt++;
//     while (true)
//     {
//         std::cout << "get a sig: " << signo << ", cnt: " << cnt << std::endl;
//         // PirintBLock();
//         PrintPending();
//         sleep(1);
//         // break;
//     }
//     // exit(1);
// }// int main()
// {
//     struct sigaction act, oact;
//     act.sa_handler = handler;
//     sigemptyset(&act.sa_mask);
//     sigaddset(&act.sa_mask, 3);
//     sigaddset(&act.sa_mask, 4);
//     sigaddset(&act.sa_mask, 5);
//     sigaddset(&act.sa_mask, 6);
//     sigaddset(&act.sa_mask, 7);//     ::sigaction(2, &act, &oact);//     while (true)
//     {
//         // PirintBLock();
//         PrintPending();
//         pause();
//     }
// }

板书笔记:


http://www.ppmy.cn/server/142921.html

相关文章

前端无感刷新token

摘要&#xff1a; Axios 无感知刷新令牌是一种在前端应用中实现自动刷新访问令牌&#xff08;access token&#xff09;的技术&#xff0c;确保用户在进行 API 请求时不会因为令牌过期而中断操作 目录概览 XMLHttpRequestAxiosFetch APIJQuni.request注意事项&#xff1a; 访问…

Xss挑战(跨脚本攻击)

Xss挑战&#xff08;跨脚本攻击&#xff09; 首先在kali中下载xss 可以使用命令docker search xss-labs 下载xss docker pull vulfocus/xss-labs 运行容器&#xff0c;映射到8088端口加载镜像 Docker run -dt -p 8088:80 vulfocus/xss-labs 用浏览器访问127.0.0.1:8088 开启…

NoSQL大数据存储技术测试(4)Cassandra的原理和使用

单项选择题 第1题 Cassandra的特点不包括&#xff08;&#xff09;。 节点对称 去中心化 强调高一致性 &#xff08;我的答案&#xff09; 支持异构设备 第2题 Cassandra采用&#xff08;&#xff09;实现分布式环境的拓扑划分。 Paxos算法 CAP原理 布隆过滤器 一致…

Java Function 的妙用:化繁为简的魔法师!

Java Function 的妙用&#xff1a;化繁为简的魔法师&#xff01; 在 Java 开发中&#xff0c;Function 是一个非常重要的函数式接口&#xff0c;它的存在让代码从繁琐走向简洁&#xff0c;从普通迈向优雅。今天&#xff0c;我们就来聊聊 Function 的那些“妙用”&#xff0c;以…

SRP 实现 Cook-Torrance BRDF

写的很乱&#xff01; BRDF&#xff08;Bidirectional Reflectance Distribution Function&#xff09;全称双向反射分布函数。辐射量单位非常多&#xff0c;这里为方便直观理解&#xff0c;会用非常不严谨的光照强度来解释说明。 BRDF光照模型&#xff0c;上反射率公式&#…

nodejs+mysql+vue3 应用实例剖析

文章目录 node.js vue3 mysql 应用后端实现&#xff08;koa部分&#xff09;1. 项目初始化与依赖安装2. 目录结构3. config/db.js - 数据库配置与连接4. models/user.js - 用户模型及数据库操作5. controllers/authController.js - 认证控制器6. controllers/userController.j…

VScode+opencv——关于opencv多张图片拼接成一张图片的算法

用于显示多张图片——变量为图片组&#xff0c;图像尺寸&#xff0c;间隙&#xff0c;边界值&#xff0c;输出图片 #include <iostream> #include <opencv2/opencv.hpp>using namespace cv; using namespace std;//用于显示多张图片,变量为图片组&#xff0c;图像…

vue之axios根据某个接口创建实例,并设置headers和超时时间,捕捉异常

import axiosNew from axios;//给axios起个别名//创建常量实例 const instanceNew axiosNew.create({//axios中请求配置有baseURL选项&#xff0c;表示请求URL的公共部分&#xff0c;url baseUrl requestUrlbaseURL: baseURL,//设置超时时间为20秒timeout: 20000,headers: {…