结合进程->信号结论
信号是如何记录的?
实际上,当一个进程接收到某种信号后,该信号是被记录在该进程的进程控制块当中的。我们都知道进程控制块本质上就是一个结构体变量,而对于信号来说我们主要就是记录某种信号是否产生,因此,我们可以用一个32位的位图来记录信号是否产生。
如何理解信号发送的本质
#include
#include
#include
#include
#include
using namespace std;
void catchSig(int signum)
{
cout << "进程捕捉到了一个信号,正在处理中: " << signum <<"Pid: " << getpid()<
理解除0错误
一旦出现硬件异常,进程不一定会退出(虽然一般默认是退出的)
一个程序中发生了死循环,主要是因为寄存器中的异常一直没有被解决
对信号的总结: 所有的信号,都有他的来源,但最终全部都是被OS识别,解释,并发送的!
用户级页表 && 内核级页表
CR3 -> 表示当前CPU的执行权限 1内核,3用户态
SIGKILL和SIGSTOP
#include
#include
#include
#include
void catchSig(int signum)
{
std::cout << "获取一个信号: " << signum << std::endl;
}
int main()
{
// 9号进程无法被屏蔽或者阻塞
for(int sig = 1; sig <= 31; sig++) signal(sig, catchSig);
while(true) sleep(1);
return 0;
}
#include
#include
#include
#include
static void handler(int signum)
{
std::cout << "捕捉 信号: " << signum << std::endl;
// 不要终止进程,exit
}
static void showPending(sigset_t& pending)
{
for (int sig = 1; sig <= 31; sig++)
{
if (sigismember(&pending, sig))
std::cout << "1";
else
std::cout << "0";
}
std::cout << std::endl;
}
int main()
{
// 0. 方便测试,捕捉2号信号,不要退出
signal(2, handler);
// 1. 定义信号集对象
sigset_t bset, obset;
sigset_t pending;
// 2. 初始化
sigemptyset(&bset);
sigemptyset(&obset);
sigemptyset(&pending);
// 3. 添加要进行屏蔽的信号
sigaddset(&bset, 2 /*SIGINT*/);
// 4. 设置set到内核中对应的进程内部[默认情况进程不会对任何信号进行block]
int n = sigprocmask(SIG_BLOCK, &bset, &obset);
assert(n == 0);
(void)n;
std::cout << "block 2 号信号成功...., pid: " << getpid() << std::endl;
// 5. 重复打印当前进程的pending信号集
int count = 0;
while (true)
{
// 5.1 获取当前进程的pending信号集
sigpending(&pending);
// 5.2 显示pending信号集中的没有被递达的信号
showPending(pending);
sleep(1);
count++;
if (count == 20)
{
// 默认情况下,恢复对于2号信号的block的时候,确实会进行递达
// 但是2号信号的默认处理动作是终止进程!
// 所以需要对2号信号进行捕捉
std::cout << "解除对于2号信号的block" << std::endl;
int n = sigprocmask(SIG_SETMASK, &obset, nullptr);
assert(n == 0);
(void)n;
}
}
return 0;
}
#include
#include
#include
#include
static void showPending(sigset_t& pending)
{
for (int sig = 1; sig <= 31; sig++)
{
if (sigismember(&pending, sig))
std::cout << "1";
else
std::cout << "0";
}
std::cout << std::endl;
}
static void blockSig(int sig)
{
sigset_t bset;
sigemptyset(&bset);
sigaddset(&bset, sig);
int n = sigprocmask(SIG_BLOCK, &bset, nullptr);
assert(n == 0);
(void)n;
}
int main()
{
for (int sig = 1; sig <= 31; sig++)
{
blockSig(sig);
}
sigset_t pending;
while (true)
{
sigpending(&pending);
showPending(pending);
sleep(1);
}
return 0;
}
#!/bin/bash
i=1
id=$(pidof signal)
while [ $i -le 31 ]
do
if [ $i -eq 9 ];then
let i++
continue
fi
if [ $i -eq 19 ];then
let i++
continue
fi
kill -$i $id
echo "kill -$i $id"
let i++
sleep 1
done
#include
#include
#include
#include
using namespace std;
void showPending(sigset_t *pending)
{
for(int sig = 1; sig <= 31; sig++)
{
if(sigismember(pending, sig)) cout << "1";
else cout << "0";
}
cout << endl;
}
void handler(int signum)
{
cout << "获取了一个信号: " << signum << endl;
sigset_t pending;
int c = 20;
while(true)
{
sigpending(&pending);
showPending(&pending);
c--;
if(!c) break;
sleep(1);
}
}
int main()
{
// signal(2, SIG_IGN);
cout << "getpid: " << getpid() << endl;
// 内核数据类型,用户栈定义的
struct sigaction act, oact;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = handler;
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);
// 设置进当前调用进程的pcb中
sigaction(2, &act, &oact);
cout << "default action : " << (oact.sa_handler) << endl;
while(true) sleep(1);
return 0;
}
#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
pid_t id = fork();
if(id == 0)
{
sleep(1);
int a = 100;
a /= 0;
exit(0);
}
int status = 0;
waitpid(id, &status, 0);
cout << "父进程:" << getpid() << " 子进程:" << id << \
" exit sig: " << (status & 0x7F) << " is core: " << ((status >> 7) & 1) << endl;
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef function func;
vector callbacks;
uint64_t count = 0;
void showCount()
{
// cout << "进程捕捉到了一个信号,正在处理中: " << signum << " Pid: " << getpid() << endl;
cout << "final count : " << count << endl;
}
void showLog()
{
cout << "这个是日志功能" << endl;
}
void logUser()
{
if(fork() == 0)
{
execl("/usr/bin/who", "who", nullptr);
exit(1);
}
wait(nullptr);
}
// 定时器功能
// sig:
void catchSig(int signum)
{
for(auto &f : callbacks)
{
f();
}
//alarm(1);
}
static void Usage(string proc)
{
cout << "Usage:\r\n\t" << proc << " signumber processid" << endl;
}
void handler(int signum)
{
sleep(1);
cout << "获得了一个信号: " << signum << endl;
exit(1);
}
int main(int argc, char* argv[])
{
signal(SIGALRM, catchSig);
alarm(1); // 设定了一个闹钟,这个闹钟一旦触发,就自动移除了
callbacks.push_back(showCount);
callbacks.push_back(showLog);
callbacks.push_back(logUser);
while(true) count++;
return 0;
}
可重入函数:
不可重入函数
#include
#include
#include
#include
using namespace std;
int flag = 0;
void changeFlag(int signum)
{
(void)signum;
cout <<"change flag: "<< flag;
flag = 1;
cout << "->" << flag << endl;
}
int main()
{
signal(2, changeFlag);
while(!flag);
cout << "进程正常退出后:" << flag << endl;
}
volatile int flag = 0;
#include
#include
#include
#include
using namespace std;
void handler(int signum)
{
cout << "子进程退出: " << signum << " fater: " << getpid() << endl;
}
// 证明 子进程退出,会想父进程发送信号
int main()
{
signal(SIGCHLD, handler);
if (fork() == 0)
{
cout << "child pid: " << getpid() << endl;
sleep(1);
exit(0);
}
while (true) sleep(1);
}
#include
#include
#include
#include
using namespace std;
// 如果我们不想等待子进程,并且我们还想让子进程退出之后,自动释放僵尸子进程
int main()
{
// OS 默认就是忽略的
signal(SIGCHLD, SIG_IGN); // 手动设置对子进程进行忽略
if(fork() == 0)
{
cout << "child: " << getpid() << endl;
sleep(5);
exit(0);
}
while(true)
{
cout << "parent: " << getpid() << " 执行我自己的任务!" << endl;
sleep(1);
}
}
signal(SIGCHLD, SIG_IGN); // 手动设置对子进程进行忽略