尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux kill rise abort 函数

Linux kill rise abort 函数 core文件当进程异常终止时会生成core文件需要进行相应设置可以通过gdb调试查看错误调试以下程序生成调试core文件需要做以下几步使用ulimit -a查看资源上限修改core sizeulimit -c core-size在编译运行程序时加上-g选项使得能够被gdb调试运行后生成core文件调试core程序gdb test进入gdb终端使用core-file core可以查看core定位错误killint kill(pid_t pid, int sig);使用man 2 kill查看帮助功能给任何的进程或者进程组pid发送任何的信号sig参数pid 0: 将信号发送给指定的进程 0: 将信号发送给当前的进程组 -1: 将信号发送给每一个有权限接收这个信号的进程 -1: 这个pid某个进程组的ID取反sig: 需要发送的信号的编号或者是宏值0表示不发送任何信号返回值0成功-1失败raiseint raise(int sig);使用man 3 raise查看帮助功能给当前进程发送信号参数sig: 要发送的信号返回值0成功非0失败abortvoid abort(void);使用man 3 abort查看帮助功能 发送SIGABRT信号给当前的进程杀死当前进程alarm代码逐行运行过程1. 第 26-27 行int seconds alarm(5);动作设置一个 5 秒后触发的定时器。返回值由于在此之前没有设置过任何定时器alarm(5)返回0。输出seconds 02. 第 29 行sleep(2);动作程序主动休眠 2 秒。状态此前设置的 5 秒定时器倒计时经过了 2 秒还剩3 秒。3. 第 30-31 行seconds alarm(2);动作重置定时器为 2 秒。这次调用会取消之前未完成的定时器并返回原定时器还剩的秒数。返回值原定时器还剩 3 秒因此返回3。输出seconds 34. 第 33-35 行while(1) { }动作程序进入死循环。后续经过 2 秒后第 30 行重新设置的定时器到期操作系统会向该进程发送SIGALRM信号。由于代码中没有注册自定义的信号处理函数系统会执行默认动作——直接终止进程。实际时间运行结果与分析:直接运行程序发现程序运行了约2-3秒才停止且打印的数字只有约17万。原因:往终端屏幕输出数据属于IO操作非常耗时。程序大部分时间都花在了打印上而不是真正的数数。优化验证: 将输出重定向到文件./alarm1 a.txt程序会立即在1秒后结束。查看文件发现数字达到了约1085万。结论: 重定向到文件后IO操作次数减少更能体现CPU的真实运算速度。实际运行时间 内核时间 用户时间 消耗时间操作内存内核时间、用户时间的速度远快于操作硬件消耗时间。因此当程序主要进行IO操作时消耗时间会占据主导。:alarm() 定时器采用的是自然定时法与进程的状态无关。哪怕是sleep也会继续倒计时setitimerint setitimer(int which, const struct itimerval *new_val, struct itimerval *old_value);非阻塞使用man 2 setitimer查看帮助功能设置定时器闹钟。可以替代alarm函数。精度微妙us可以实现周期性定时参数which: 定时器以什么时间计时ITIMER_REAL: 真实时间时间到达发送SIGALRM(常用)ITIMER_VIRTUAL: 用户时间时间到达发送SIGVTALRMITIMER_PROF: 以该进程在用户态和内核态下所消耗的时间来计算时间到达发送SIGPROFnew_value: 设置定时器的属性old_value记录上一次的定时的时间参数一般不使用指定NULL返回值成功 0失败 -1 并设置错误号struct itimerval { // 定时器的结构体 struct timeval it_interval; // 每个阶段的时间间隔时间 struct timeval it_value; // 延迟多长时间执行定时器 }; struct timeval { // 时间的结构体 time_t tv_sec; // 秒数 suseconds_t tv_usec; // 微秒 }; // 过it_value秒后每隔it_interval秒定时一次signal#include signal.h typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); - 功能设置某个信号的捕捉行为 - 参数 - signum: 要捕捉的信号 - handler: 捕捉到信号要如何处理 - SIG_IGN : 忽略信号 - SIG_DFL : 使用信号默认的行为 - 回调函数 这个函数是内核调用程序员只负责写捕捉到信号后如何去处理信号。 回调函数 - 需要程序员实现提前准备好的函数的类型根据实际需求看函数指针的定义 - 不是程序员调用而是当信号产生由内核调用 - 函数指针是实现回调的手段函数实现之后将函数名放到函数指针的位置就可以了 - 返回值 成功返回上一次注册的信号处理函数的地址。第一次调用返回NULL 失败返回SIG_ERR设置错误号 SIGKILL SIGSTOP不能被捕捉不能被忽略。回调函数为什么定义了一个名为sighandler_t的“函数指针类型”在 C 语言中函数不能作为值被传递或返回只有函数的地址指针才可以而我们的需求是在调用signal函数时将函数作为值或者理解为触发条件被传递所以要定义函数类型指针信号捕捉必须放在定时器之前:否则可能导致信号丢失进程被默认终止。SIGKILL 和 SIGSTOP 不能被捕捉或忽略: 这是系统安全机制防止恶意进程无法被杀死。如果尝试捕捉 SIGKILLsignal() 函数会返回 SIG_ERR设置失败。过3秒以后每隔2秒钟定时一次的定时器功能如果不加信号捕捉无法执行间隔两秒这个操作ret执行完直接技术进程#include sys/time.h #include stdio.h #include stdlib.h #include signal.h //编写回调函数 void myalrm(int num) {//num是在信号触发时由 Linux 操作系统内核自动传给 myalarm 函数的。 printf(print %d\n, num); } int main() { //注册信号捕捉 signal(SIGALRM, myalrm); //设置时间间隔 struct itimerval new_value; new_value.it_interval.tv_sec 2; new_value.it_interval.tv_usec 0; // 设置延迟的时间,3秒之后开始第一次定时 new_value.it_value.tv_sec 3; new_value.it_value.tv_usec 0; int ret setitimer(ITIMER_REAL, new_value, NULL); // 非阻塞的 printf(定时器开始了...\n); if (ret -1) { perror(setitimer); exit(0); } getchar();//等待输入防止程序结束 return 0; }注册信号捕捉程序向 Linux 内核注册当收到SIGALRM闹钟信号时不要执行默认的终止程序操作而是自动回调执行myalarm函数。配置定时器参数new_value.it_value首次触发延迟设置为 3 秒。new_value.it_interval周期触发间隔设置为 2 秒。启动定时器调用setitimer(ITIMER_REAL, new_value, NULL);根据真实物理时间ITIMER_REAL启动倒计时。setitimer是非阻塞的调用后立即返回并打印定时器开始了...\n主线程不会在此停留等待。主线程等待与内核回调执行到getchar();主线程暂停等待用户在终端输入字符。3秒后定时器首次到期内核向进程发送SIGALRM信号。主线程被打断自动调用回调函数myalarm输出信号及其相关函数、1. 用户通过键盘 Ctrl C产生 2 号信号 SIGINT信号被创建2. 信号产生但是没有被处理 未决在内核中将所有的没有被处理的信号存储在一个集合中 未决信号集SIGINT 信号状态被存储在第二个标志位上这个标志位的值为 0 说明信号不是未决状态这个标志位的值为 1 说明信号处于未决状态3. 这个未决状态的信号需要被处理处理之前需要和另一个信号集阻塞信号集进行比阻塞信号集默认不阻塞任何的信号如果想要阻塞某些信号需要用户调用系统的 API4. 在处理的时候和阻塞信号集中的标志位进行查询看是不是对该信号设置阻塞了如果没有阻塞这个信号就被处理如果阻塞了这个信号就继续处于未决状态直到阻塞解除这个信号就被处理未决产生信号键盘输入但是被阻塞住了系统默认0阻塞调用系统api进行阻塞系统默认0不阻塞未决信号集由内核系统操作用户不可以改变如果信号被发送了原来未决信号集相应信号就要变成0操作自定义信号集函数(sigemptyset等)int sigemptyset(sigset_t *set);功能清空信号集中的数据将信号集中的所有的标志位置为0参数set传出参数需要操作的信号集返回值成功返回0 失败返回-1int sigfillset(sigset_t *set);功能将信号集中的所有的标志位置为1参数set传出参数需要操作的信号集返回值成功返回0 失败返回-1int sigaddset(sigset_t *set, int signum);功能设置信号集中的某一个信号对应的标志位为1表示阻塞这个信号参数set传出参数需要操作的信号集signum需要设置阻塞的那个信号返回值成功返回0 失败返回-1int sigdelset(sigset_t *set, int signum);功能设置信号集中的某一个信号对应的标志位为0表示不阻塞这个信号参数set传出参数需要操作的信号集signum需要设置不阻塞的那个信号返回值成功返回0 失败返回-1int sigismember(const sigset_t *set, int signum);功能判断某个信号是否阻塞参数set传入参数需要操作的信号集signum需要判断的那个信号返回值1 signum被阻塞0 signum不阻塞-1 失败操作内核信号集函数(sigprocmask sigpending)int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);使用man 2 sigprocmask查看帮助功能将自定义信号集中的数据设置到内核中设置阻塞解除阻塞替换参数how: 如何对内核阻塞信号集进行处理SIG_BLOCK: 将用户设置的阻塞信号集添加到内核中内核中原来的数据不变。假设内核中默认的阻塞信号集是mask 相当于mask | setSIG_UNBLOCK: 根据用户设置的数据对内核中的数据进行解除阻塞。相当于mask ~setSIG_SETMASK覆盖内核中原来的值set已经初始化好的用户自定义的信号集oldset: 保存设置之前的内核中的阻塞信号集的状态一般不使用设置为 NULL 即可返回值成功返回0 失败返回-1int sigpending(sigset_t *set);使用man 2 sigpending查看帮助功能获取内核中的未决信号集参数set传出参数保存的是内核中的未决信号集中的信息返回值成功返回0 失败返回-1先把自定义信号集东西设置好再“映射到内核阻塞信号集”。总结不管是未决信号集还是阻塞信号集内核里面的两个集都没法直接更改。其中内核未决信号集压根动不了内核阻塞信号集可以通过sigprocmask api将原先自定义的信号集设置给内核打印1-32号信号中未决情况1.建立自定义信号集并清空里面数据2.将要设置阻塞的信号在自定义信号集中设置好3.通过sigprocmask把自定义信号集里面的设置到内核中4.开启循环创建一个计数器和一个新的信号集接受内核未决信息5.获取内核信息6.把1-32信号未决状态输出只有在终端输入ctrl c 时候2号未决状态才会变为1在没有任何外界触发时内核的未决信号集Pending set默认全为 0。因此打印结果是全0按下ctrl c 信号触发又因为设置成阻塞2号变为未决状态。当解除阻塞信号发送到进程进程终止2号未决变为0#include stdio.h #include signal.h #include stdlib.h #include unistd.h int main() { // 设置自定义信号集 sigset_t set; // 清空信号集 sigemptyset(set); // 设置2 3号信号阻塞 sigaddset(set, SIGINT); sigaddset(set, SIGQUIT); // 修改内核中的阻塞信号集 sigprocmask(SIG_BLOCK, set, NULL); int num 0; // 循环获取当前的未决信号集的数据 while (1) { // 计数用以退出循环 num; sigset_t pendingset; // 清空 sigemptyset(pendingset); // 获取当前的未决信号集的数据 sigpending(pendingset); // 遍历前32位 for(int i 1; i 31; i) { if(sigismember(pendingset, i) 1) { printf(1); }else if(sigismember(pendingset, i) 0) { printf(0); }else { perror(sigismember); exit(0); } } printf(\n); sleep(1); if(num 10) { // 解除阻塞 sigprocmask(SIG_UNBLOCK, set, NULL); } } return 0; }内核实现信号捕捉过程sigactionint sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);使用man 2 sigaction查看帮助功能检查或者改变信号的处理即信号捕捉参数signum: 需要捕捉的信号的编号或者宏值信号的名称act捕捉到信号之后的处理动作oldact: 上一次对信号捕捉相关的设置一般不使用设置为NULL返回值成功返回0 失败返回-1SIGCHLD触发条件触发条件三种情况:子进程终止时: 子进程运行结束或异常终止这是最常见的情况。子进程收到SIGSTOP信号停止时: 子进程被暂停注意SIGSTOP是暂停进程不是终止。子进程从停止态被唤醒时: 子进程处于暂停状态收到SIGCONT信号后恢复运行。
返回列表