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();
// }
// }