欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

信号----进阶总结:

程序员文章站 2022-03-19 13:21:49
...

总结:

信号:

信号的生命周期:信号的产生-》在进程中注册-》在进程中注销-》信号处理

信号的产生:

硬件长产生:Ctrl+c 中断信号 Ctrl+|      Ctrl +z进程停止

软件产生:kill -[signum]  就是上面信号的数字(这些数字就是宏) -p pid (向指定进程发送指定信号)

系统调用接口 man 2 kill,----->int kill(pid_t pid, int sig);

 

 

信号在进程中的注册:在进程pcb中做标记,标记进程收到了哪些信息

task_struct结构体中,有个sigpending(未决),

我们把信号加入到进程的过程称为

注册

 

信号----进阶总结:

 

 

 

非可靠信号:pcb中pending位图中是否注册,是,就不做任何操作。不是就注册

可靠信号:pcb都进行注册

 

注销

信号在进程中的注销

    非可靠信号:节点只有一个,注销就是删除节点,位图置0

    可靠信号:节点有多个,删除一个节点,要判断是否有相同信号节点。如果没有就信号置0.如果还有就不处理位图。

信号的处理

信号的处理并不是立即被处理;而是选择 一个合适的实际进行处理信号。当进程运行从内核态返回用户态的时候,就会去执行这个信号。

        问题:进程如何从用户态切换到内核态:发起系统调用;程序异常;中断(硬件中断Ctrl+c);

        进程当前运行的代码是用户或者是库函数,就说进程当前运行在用户态

信号的处理方式:

        默认的处理方式--既定义好的处理方式

        忽略处理方式--处理动作什么都不做

        自定义处理方式--用户自己定义的处理方式----修改默认的处理函数(自定义一个处理函数去替换默认的处理函数)

如何修改信号的处理方式:

   1   、  sighandler_t    signal(int signum    ,sighander_t  handler);

信号会打断当前的阻塞操作

                    signum :信号的编码 ---替换signum这个信号的处理函数(也可以是信号名,信号名和数字是宏,可以替换)

                    handler:函数指针 用户传入的处理函数

                        SIG_DFL:信号的默认处理动作(default)

                        SIG_IGN:信号的忽略处理动作(ignore)

                        typedef void(*sighandler_t)(int);//定义了一个函数指针类型,这个函数指针类型是*sighandler_t,返回值是void,参数是int

          

  1 #include <unistd.h>

  2 #include <stdio.h>

  3 #include <signal.h>

  4#include<stdlib.h>                                                                                                  

  5

  6 int main (){

  7   signal(SIGINT, SIG_IGN);  // 也可以换成signal(2, 3);  2号信号被替换成3号信号

  8   while(1){

  9     printf("xiuxiyihui\n");

10     sleep(10);

11   }

12   system("pasue");

13   return 0;

14 }

 

 

2、int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);  将信号signum结构被后面的*act结构替换,同时将signum的结构保存到*oldact结构中

 

 

struct sigaction {

               void     (*sa_handler)(int);   ---->参入的参数是现有的信号数字,并对现有信号进行处理

               void     (*sa_sigaction)(int, siginfo_t *, void *);      //这两个其实是一个联合体,二选一运用

               sigset_t   sa_mask;    ------>当我们正在处理这个信号时,sa_mask形成一个阻塞,别的信号不能处理

sigset_t   sa_mask;这里的sigset是个位图结构,由于这个位图是直接从内存中分配来的,他原来的信息需要清空才能保证我们使用位图时的正确性

               int        sa_flags;      -->这是一个标识,通常标记为0,就是使用上面sa_handler函数;标记为SA_SIGINFO,就是使用sa_sigaction的函数

               void     (*sa_restorer)(void);

           };

 

 1 #include <unistd.h>                                                                                                  

 2 #include <stdio.h>

 3 #include <signal.h>

 4 #include <stdlib.h>

 5

 6 int main (){

 7  

 8   struct sigaction new_act, old_act;

 9   new_act.sa_flags = 0;

10   new_act.sa_handler = SIG_IGN;

11

12 // int sigemptyset(sigset_t *set)  清空信号的集合

13   sigemptyset(&new_act.sa_mask);//清空的是结构体中的位图

14   sigaction(2, &new_act, &old_act);

15

16   while(1){

17     printf("xiuxiyihui\n");

18     sleep(10);

19   }

自定义信号在对操作函数的改变上可以传入已经定义好的信号,也可以直接传入函数指针就可以

1 #include <unistd.h>                                                                                                  
2 #include <stdio.h>
3 #include <signal.h>
4 #include <stdlib.h>
5
6 void rec(int signo){
7   signal(signo, SIG_DFL);
8   printf("%d已经恢复\n",signo);
9 }
10
11
12 
13 int main (){
14  //1 signal(SIGINT, SIG_IGN);
15   struct sigaction new_act, old_act;
16   new_act.sa_flags = 0;
17   new_act.sa_handler = rec;
18
19   sigemptyset(&new_act.sa_mask);//清空的是结构体中的位图
20
21   sigaction(2, &new_act, &old_act);
22
23   while(1){
24     printf("xiuxiyihui\n");
25     sleep(10);
26   }
27   system("pasue");
28   return 0;
29 }     

信号的阻塞

阻止信号被抵达--》阻止信号被处理

信号可以注册,但是不被处理(进程信号中位图置1,链表里加入了信号,)

在pcb中还有一个阻塞信号集合【标记哪些信号不被处理】

 

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

        how:

                SIG_BLOCK 向阻塞集合中加入set集合中的信号block = mask | set

                SIG_UNBLOCK 把阻塞的集合中移除set集合中的信号 block = mask &(~set)

                SIG_SETMASK 将set集合信号设置为阻塞集合 block= set

        oldset:

            用于保存修改前的信号

关键函数

            sigfillset(sigset_t *set)向set中添加所有信号

            sigaddset(sigset_t* set, int signum)向set中添加指定信号

 

在所有的信号中,9号信号SIGKILL和19号信号SIGSTOP不可以阻塞,他们不能加入到block中进行阻止

调研sleep函数的实现

 

 

可重入和不可重入

 

 

函数的重入:

            可重入:多个执行流程同时执行进入相同的函数

            不可重入: 多个执行流程同时执行进入相同的函数,有可能造成数据的二义性以及代码逻辑混乱

当用户设计一个函数或者使用一个函数时,在多个执行流中,这个时候就要考虑函数是否允许重入

 

函数的可重入和不可重入关键是:

             这个函数中是否对临界资源(全局数据)进行来非原子操作