目录
一、内核态与用户态的切换
二、 sigaction
参数介绍编辑
三、 signal
四、某个信号在正在捕捉期间,该信号不允许再次被递达
五、可重入与不可重入函数(描述函数的特性)
六、volatile关键字
七、SIGCHLD信号
一、内核态与用户态的切换
cpu执行的我们的代码,不只是用户层级的。我们代码牵扯大量的系统调用,系统调用属于OS
因此调用系统调用的时候,属于内核态,执行系统调用属于内核的数据,因此需要将身份从用户态切换到内核态。
用户态:只能访问自己的代码和数据
内核态:访问内核的代码和数据
收到信号,进入内核(block、pending、handler三张表),调用handler方法,重新进入用户,用户代码执行结束重新返回内核。
二、 sigaction
参数介绍
struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);
};
三、 signal
signal除了可以自定义传入方法,还可以将参数二设置为:SIG_IGN(忽略。注意:忽略是收到了,但是不处理),SIG_DFL(默认方法)
signal处理方式:默认 忽略 自定义
四、某个信号在正在捕捉期间,该信号不允许再次被递达
再次发送二号信号,发现二号信号而屏蔽(block表)+阻塞(pending表)
五、可重入与不可重入函数(描述函数的特性)
以下是一个不可重入函数的例子:
int counter = 0;void increment() {counter++; // 使用了全局变量
}void thread_function() {for (int i = 0; i < 1000; i++) {increment(); // 如果多个线程同时调用increment,会导致竞态条件}
}
1.可通过加锁来保护数据从而让函数可重入。2.不让该函数被多执行流重复进入
六、volatile关键字
#include <stdio.h>
#include <signal.h>
int flag = 0;
void handler(int sig)
{printf("chage flag 0 to 1\n");flag = 1;
}
int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}
[hb@localhost code_test]$ cat Makefile
sig:sig.cgcc -o sig sig.c #-O2
.PHONY:clean
clean:rm -f sig
[hb@localhost code_test]$ ./sig
^Cchage flag 0 to 1
process quit normal
标准情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while 条件不满足,退出循环,进程退出
#include <stdio.h>
#include <signal.h>
int flag = 0;
void handler(int sig)
{printf("chage flag 0 to 1\n");flag = 1;
}
int main(){signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}
[hb@localhost code_test]$ cat Makefile
sig:sig.cgcc -o sig sig.c -O2
.PHONY:clean
clean:rm -f sig
[hb@localhost code_test]$ ./sig
^Cchage flag 0 to 1
^Cchage flag 0 to 1
^Cchage flag 0 to 1
七、SIGCHLD信号
但是前提是保证父进程没有退出。这样父进程就不需要阻塞等待或者轮询等待
只有子进程退出发送信号时,父进程才回去处理这个信号。
但是为了稳妥,最好是手动设置处理方式
signal(17,handler);
void handler(int signo)
{sleep(5);pid_t rid;while ((rid = waitpid(-1, nullptr, WNOHANG)) > 0){cout << "I am proccess: " << getpid() << " catch a signo: " << signo << "child process quit: " << rid << endl;}
}
注意内部需要设置WNOHANG。
将循环条件设置为等待,这样等待成功,返回1,大于0,执行循环体。下一次会再次进行循环条件的判断。
这样就算是多个进程同时结束,也可以正确等待进程(暂时未被等待的进程处在zombie状态)。