Vue框架:
Vue驾校-从项目学Vue-1
算法系列博客友链:
神机百炼
kill -l
#1~31号属于普通信号,32~64号属于实时信号
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
grep -ER 'SIGQUIT' /usr/include/
/usr/include/asm-generic/signal.h:#define SIGQUIT 3
/usr/include/mysql/private/my_config_x86_64.h:/* #undef SIGQUIT */
/usr/include/mysql/my_config_x86_64.h:/* #undef SIGQUIT */
/usr/include/bits/signum.h:#define SIGQUIT 3 /* Quit (POSIX). */
/usr/include/asm/signal.h:#define SIGQUIT 3
/usr/include/valgrind/vki/vki-ppc64-linux.h:#define VKI_SIGQUIT 3
/usr/include/valgrind/vki/vki-darwin.h:#define VKI_SIGQUIT SIGQUIT
/usr/include/valgrind/vki/vki-arm-linux.h:#define VKI_SIGQUIT 3
vim /usr/include/asm-generic/signal.h
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
//.......
背景:
当一个信号发生,但是未被执行/被阻塞时,Pending bitmap为1
同一信号又一次发生时:
Ctrl + c
kill -2 pid
Ctrl + \
kill -3 pid
Ctrl + d 退出当前会话。
Ctrl + z 将当前运行的程序放到后台运行。与运行时加&类似
Ctrl + s 暂停运行该终端
Ctrl + q 退出这种状态,让终端继续运行
使用范围:OS只允许将部分信号处理方式重新自定义
signal():
#include
sighandler_t signal(int signum, sighandler_t handler);
参数:
作用:当signum对应的信号到达时,不采用默认信号处理方法,而采用函数指针handler所指向的函数进行处理
特殊点:被OS调用,而非被main()调用
实例:
#include
#include
void handler(int signo){
printf("signal + handler\n");
return;
}
int main(){
signal(2, handler);
while(1){
printf("running...\n");
sleep(1);
}
return 0;
}
sigaction():
#include
sigaction(int signo,struct sigaction *act, struct sigaction *oldact);
作用:自定义修改指定signo号信号的处理方法,并保存原本的信号处理方法
特殊点:被OS调用,而非被main()调用
参数:
信号编号:针对signo号信号进行自定义函数处理
struct sigaction:函数指针+变量,其实是个类
struct sigaction{
void (*sa_handler)(int); //自定义处理函数
void (*sa_sigaction)(int, siginfo_t *, void *); //处理实时信号
sigset_t sa_mask; //阻塞集
int sa_falgs; //flag==0即可
void (*sa_restorer)(void);
};
返回值:
实例:
#include
#include
#include
#include
struct sigaction act, oldact;
void handler(int signo){
printf("捕获到%d号信号\n", signo);
sigaction(SIGINT, &oldact, NULL);
return ;
}
int main(){
//1,准备好输入输出变量
memset(&act, 0, sizeof(act));
memset(&oldact, 0, sizeof(oldact));
//2,自定义信号处理
act.sa_handler = handler; //自定义处理函数
act.sa_flags = 0; //flag为0即可
sigemptyset(&act.sa_mask); //不设阻塞集
//3,落实对信号处理方法的修改
sigaction(SIGINT, &act, &oldact);
while(1){
printf("进程pid:%d", getpid());
sleep(1);
}
return 0;
}
与signal()的区别:
raise():
#include
int raise(int sig);
作用:
执行该函数时,进程向自己发送sig号信号
常常搭配signal()自定义处理函数使用
实例:
#include
#include
void handler(int signo){
printf("进程id:%d\n", getid());
return;
}
int main(){
signal(2, handler);
while(1){
sleep(1);
raise(2);
}
return 0;
}
alarm():
#include
alarm(int seconds);
参数:seconds为秒数,过seconds秒后触发14号的闹钟信号SIGALRM
作用:
实例:粗略查看计算机1s内做多少次加法
#include
#include
#include
#include
int count;
void handler(int signo){
printf("count:%d\n", count);
alarm(1);
return;
}
int main(){
signal(SIGALRM, handler);
alarm(1);
while(1){
count++;
}
return 0;
}
kill():
#include
#Include <signal.h>
int kill(pid, int signo);
作用:
向指定pid所属进程发送signo信号
实例:
#include
#include <>
int main(){
while(1){
pid_t pid = getpid();
printf("该进程pid:%d\n",pid);
sleep(1);
}
return 0;
}
#include
#include
#incllude <sys/types.h>
#include
int main(int argc, char* argv[]){
if(argc != 3){
printf("%s正确用法:kill pid signo", argv[0]);
return -1;
}
pid_t pid = atoi(argv[1]);
int signo = atoi(argv[2]);
kill(pid, signo);
return 0;
}
./killed #打印该进程pid
./killtest pid 2
abort():
#include
void abort(void)
作用:
终止进程,比exit()更为强制。
即使通过signal() / sigaction()重写了信号处理方法,之后也会终止进程
原理:
向进程发送6号信号,SIGABRT
实例:
#include
#include
#include
#include
void handler(int signo){
printf("%d号信号被捕捉\n",signo);
return;
}
int main(){
signal(6, handler);
while(1){
printf("pid:%d\n",getpid());
sleep(1);
abort();
}
return 0;
}
信号阻塞:被阻塞的信号保持在未决状态,pending位图中该信号为1
解除阻塞:解除阻塞后,信号开始递达,递达之后pending位图中该信号为0
非实时信号阻塞:
一个处于阻塞中的非实时信号,未解除阻塞前,如果又继续收到了多次该信号,则解除阻塞后也只能去处理最新的那一个该信号
实时信号阻塞:
一个处于阻塞中的实时信号,未解除阻塞前,如果又继续收到了多次该信号,则信号陆续存储到队列中,解除阻塞后遍历队列陆续都被处理
进程的虚拟地址空间:
所有进程统一由OS调度:所有进程内核空间中的代码和数据一样
内核态和用户态差别:
本质:cpu中CR3寄存器和页表寄存器内容修改
用户态切换为内核态的时机:
内核态切换为用户态的时机:
信号何时被处理:当进程从内核态切换回到用户态时
信号参与的进程状态切换流程:
问:为什么handler()函数不能直接由内核态执行?
答:
物理上:OS属于内核页表映射结果,handler()函数属于用户级页表映射结果
逻辑上:OS不信任任何用户,防止handler()函数内部含有非法/越权操作
结论:内核态的进程可以读用户空间内的内容,但是不能执行用户空间内的程序
本质:类/结构体
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
作用:对进程的信号block位图/pending位图某位置为0/1,其中的0/1就是sigset_t
sigprocmask():
#include
int sigprocmask(int how, const sigset_t *newset, sigset_t *oldset);
作用:将本进程的block位图/屏蔽集设置为newset,同时将本进程的原本block位图/屏蔽集输出到oldset中
参数:
本质:通过系统调用接口让OS修改当前进程task_struct中的block位图
sigemptyset():
#include
sigemptyset(sigset_t *set);
作用:将信号block位图/屏蔽集每一位设置为0,但是只是对变量的内容修改,只有通过sigprocmask()才能对进程生效
用例:
#include
#include
int main(){
sigset_t set;
sigemptyset(&set);
//后续继续对屏蔽集set处理,再通过sigprocmask()函数调用OS系统调用接口,修改本进程的信号屏蔽集
return 0;
}
sigfillset():
#include
sigfillset(sigset_t *set);
作用:将信号block位图/屏蔽集每一位设置为1,但是只是对sigset_t变量的设置,还未通过sigprocmask()正式修改进程
sigaddset():
#include
sigaddset(sigset_t *set, unsigned int x);
作用:将现有的信号block位图/屏蔽集的第x位置为1,标识新增屏蔽x号信号
sigpending():
#include
sigpending(sigset_t *set);
作用:获取当前进程的pending位图/未决位图
输出型参数:set,将当前进程的未决位图输出到set中(pending位图中0表示该信号未产生,1表示该信号已产生)
使用前提:准备好全0的sigset_t *
#include
#include
int main(){
sigset_t set;
sigemptyset(&set);
sigpending(&set);
//set中此时就是当前进程的未决信号集
}
sigismember():
#include
sigismember(sigset_t *pending, int x);
作用:返回未决信号集/pending位图中第x位上的0/1
引申:打印当前进程完整的未决信号集
void printPending(sigset_t *pending){
int i = 1; //-std=c99会带来很多麻烦
for(i=1; i<32; i++){
if(sigismember(pending, i))
printf("1");
else printf("0");
}
printf("\n");
}
#include
#include
#include
void printPending(sigset_t &pending){
int i = 0;
for(i=1; i<32; i++){
if(sigismember(pending, i)) printf("1");
else printf("0");
}
printf("\n");
}
void handler(int signo){
printf("%d号信号脱离阻塞已经递达\n",signo);
return;
}
int main(){
//1.阻塞Ctrl + c信号
sigset_t set, oldset;
sigemptyset(&set);
sigemptyset(&oldset);
sigaddset(&set, 2);
sigprocmask(SIG_SETMASK, &set, &oldset);
//2.打印当前未决位图
sigset_t pending;
int count = 0;
while(1){
sigemptyset(&pending);
sigpending(&pending);
printPending(&pending);
sleep(1);
//3.解除对Ctrl + c信号的block
if(count>=10){
sigprocset(SIG_sETMASK, &oldset, NULL);
}
}
return 0;
}
waitpid:
int waitpid(pid_t pid, int *status, int options);
//等待成功:返回子进程pid
//等待失败:返回-1
options == 0时,父进程阻塞等待pid号子进程
waitpid:
int waitpid(pid_t pid, int *status, int options);
//等待成功:返回子进程pid
//等待失败:返回-1
options == WNOHANG时,父进程大部分时间运行自己的程序,偶尔轮询所有子进程是否终止
SIGCHLD:
子进程终止时给父进程发送SIGCHLD信号
OS对该信号的默认处理函数为忽略
父进程也可自定义该信号的处理函数
父进程自定义处理函数:
由于要清理僵尸子进程,所以还是父进程的处理函数还是需要调用wait() / waitpid()
#include
#include
#include
#include
#include
void handler(int signo){
int status;
pid_t pid;
while(pid = waitpid(-1, &status, WNOHANG) > 0){
printf("%d号子进程退出\n", pid);
printf("进程收到信号为:%d\n", status&0x7f);
printf("进程coredump为:%d\n", status&0x80);
printf("进程退出码为:%d\n", (status>>8)&0xff);
}
return ;
}
int main(){
signal(17, handler);
if(fork() == 0){
printf("%d号子进程开始运行\n", getpid());
sleep(5);
exit(100);
}
while(1);
return 0;
}
signal(17, SIG_DEL); //默认
signal(17, SIG_IGN); //忽略
#include
#include
#include
#include
#include
int main(){
signal(17, SIG_IGN);
if(fork() == 0){
printf("%d号子进程正在运行\n", getpid());
sleep(3);
exit(100);
}
while(1);
return 0;
}
while :; do ps axj | grep sigchld | grep -v grep;echo "######################" sleep 1;done
#include
#include
#include
struct sigaction act, oldact;
struct ListNode{
int val;
struct ListNode* next;
};
struct ListNode *head = (struct ListNode*) malloc(sizeof(ListNode));
void handler(){
struct ListNode *node = (struct ListNode*) malloc(sizeof(ListNode));
insert(node);
printf("信号处理函数插入一个新节点\n");
return;
}
void insert(struct ListNode* node){
node->next = head;
head = node;
return;
}
int main(){
memset(&act, 0, sizeof(act));
memset(&oldact, 0, sizeof(oldact));
act.sa_handler = handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigact(2, &act, &oldact);
struct ListNode *node = (struct ListNode*) malloc(sizeof(ListNode));
insert(node);
printf("main函数插入一个新节点\n");
return 0;
}
编译器优化级别:
CPU寄存器级别优化实例:
#include
#include
#include
int flag = 0;
void handler(int signo){
printf("get %d signal!\n",signo);
flag = 1;
return;
}
int main(){
signal(2, handler);
//flag为0时打印,发送Ctrl + c号信号后,flag==1,停止打印
while(!flag){
printf("flag == %d\n", flag);
sleep();
}
return 0;
}
运行结果:
原理分析:
#include
#include
#include
volatile int flag = 0;
void handler(int signo){
printf("get a %d signal\n", signo);
flag = 1;
return;
}
int main(){
signal(2, handler);
while(!flag){
printf("flag == %d\n", flag);
sleep(1);
}
return 0;
}