天津储鑫盛钢材现货供应商 发表于 2026-2-1 08:48:06

linux信号处理处罚机制根本(下)

发送信号

kill下令

用专门的体系下令发送信号
         kill [-信号] PID
缺省发送SIGTERM(15)信号若不指明详细信号
若要指明详细信号,可以利用信号编号,也可以利用信号名称,而且信号名称中的“SIG'前缀可以省略不写。比方
        kill -9 1234
        kil -SIGKILL 1234 5678
        kil -kill -1     (会停止当前用户下全部历程)
超等用户可以发给任何历程,而平凡用户只能发给自己的历程
#include <signal.h>
int kill(pid_t pid, int signum);
功能:向指定的历程发送信号
参数:pid 可以如下取值
        -1        -向体系中的全部历程发送信号
        >0        -向特定历程(由pid标识)发送信号
signum:信号编号,取0可用于检査pid历程是否存在,如不存在kil函数会返回-1,且errno为ESRCH
返回值:乐成(至少发出去一个信号)返回0,失败返回-1 
 代码演示

        父历程向子历程发送2号信号(别的本代码还实现了对子历程存在的判断),可以通过解释掉子历程对2号信号的捕捉实现2号信号对子历程的停止。注意,停止该历程后,由于此时没有对该历程举行收尸,代码第一次判断是该历程任然存在,经waitpid函数收尸后,该历程殒命开释剩余资源。

//发送信号
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<errno.h>
#include<sys/wait.h>
//信号处理函数
void sigfun(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
    return;
}

int main(){
    //父进程创建子进程
    pid_t pid = fork();
    if(pid == -1){
      perror("fork");
      return -1;
    }
    //子进程代码,对2号信号进行捕获处理
    if(pid == 0){
      if(signal(SIGINT,sigfun) == SIG_ERR){
            perror("signal");
            return -1;
      }
      while(1){}
      return 0;
    }
    //父进程代码,向子进程发送2号信号
    getchar();
    if(kill(pid,SIGINT) == -1){
      perror("kill");
      return -1;
    }
    //判断子进程是否存在

    getchar();
    if(kill(pid,0) == -1){
      if(errno == ESRCH){
            printf("子进程不存在\n");
      }else{
            perror("kill");
            return -1;
      }
    }else{
      printf("子进程存在\n");
      if(waitpid(pid,NULL,WNOHANG) == -1){
            perror("waitpid");
            return -1;
      }else{
            getchar();
            if(kill(pid,0) == -1){
                if(errno == ESRCH){
                  printf("子进程不存在\n");
                }else{
                  perror("kill");
                  return -1;
                }
            }
      }
    }
    return 0;
}停息

pause函数

#include <unistd.h>
int pause(void);
功能:无穷就寝
返回值:乐成壅闭,失败返回-1
        该函数使调用进(线)程进入无时限的就寝兴态,直到有信号停止了该历程或被其捕捉。假如有信号被调用历程捕捉,在信号处理处罚函数返回以后,pause函数才会返回,其返回值-1,同时置errno为EINTR,表现壅闭的被信号打断。pause函数要么不返回,要么体系返回-1,永久不会返回0.
 代码演示


//暂停
#include<stdio.h>
#include<unistd.h>
#include<signal.h>

//信号处理函数
void sigfun(int signum){
    printf("%d进程:%d号信号处理开始\n", getpid(), signum);
    sleep(5);
    printf("%d进程:%d号信号处理完毕\n", getpid(), signum);
    return;
}
int main(){
    //对2号信号进行捕获
    if(signal(SIGINT,sigfun) == SIG_ERR){
      perror("signal");
      return -1;
    }
    printf("%d进程:执行pause()函数,进入无限睡眠\n", getpid());
    int res = pause();
    printf("%d进程:pause()函数返回值:%d\n",getpid(),res);
    return 0;
}思索辨析 

        思索一下这里在代码实行过程中为什么只能通过键盘输入crtl + c按键组合,该历程才会收到2号信号进入信号处理处罚函数。我的明白是这里我们通过一个历程来实行,当我们实行kill下令时由于当进步程已经陷入了就寝,它不会自己自动发送信号,只能等候来自外部的停止(信号)。kill下令是无法通过当前一个就寝的历程来发送信号到指定历程。而键盘下令则是其他历程来控制的,它并没有就寝,因此可以通过键盘正常发送信号。
 就寝

sleep函数

#include <unistd.h>
unsigned int sleep(unsigned int seconds);
功能:有限就寝
参数:seconds         以秒为单元的就寝时限
返回值:返回0或剩余秒数。

[*]该函数使调用历程就寝seconds秒,除非有信号停止了调用历程或被其捕捉
[*]假如有信号被调用历程捕捉,在信号处理处罚函数返回以后,sleep函数才会返回且返回值为剩余的秒数,否则该函数将返回0,表现就寝富足
 usleep函数

#include <unistd.h>
int usleep (useconds t usec);
功能:更准确的有限就寝
参数:usec 以微秒(1微秒=10-6秒)为单元的就寝时限
返回值:乐成返回0,失败返回-1
        假如有信号被调用历程捕捉,信号处理处罚函数返回以后,usleep函数才会返回,且返回值为-1,同时置errno为EINTR,表现壅闭的体系调用被信号停止 
代码演示 


//睡眠
#include<stdio.h>
#include<unistd.h>
#include<signal.h>

//信号处理函数
void sigfun(int signum){
    printf("%d进程:%d号信号处理开始\n", getpid(), signum);
    sleep(5);
    printf("%d进程:%d号信号处理完毕\n",getpid(), signum);
    return;
}
int main(){
    //对2号信号进行捕获
    if(signal(SIGINT,sigfun) == SIG_ERR){
      perror("signal");
      return -1;
    }
    printf("%d进程:执行pause()函数,进入有限睡眠\n", getpid());
    int res = sleep(10);
    printf("%d进程:sleep()函数返回值:%d\n",getpid(),res);
    return 0;
} 闹钟

alarm函数

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:设置闹钟
参数:seconds 以秒为单元的闹钟时间。
返回值:返回0或先前所设闹钟的剩余秒效,

[*]alarm函数使体系内核在该函数被调用以后seconds秒的时间,向调用历程发送SIGALRM(14)信号
[*]若在调用该函数前已设过闹钟且尚未到期,则该函数会重设闹钟,并返回先前所设闹钟的剩余秒数,否则返回0
[*]若seconds取0,则表现取消先前设过且尚未到期的闹钟
代码演示 


//闹钟
#include<stdio.h>
#include<unistd.h>
#include<signal.h>

void sigfun(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
    return;
}
int main(){
    //对14号信号进行捕获处理
    if(signal(SIGALRM,sigfun) == SIG_ERR){
      perror("signal");
      return -1;
    }
    //设定闹钟
    printf("alarm(10)返回%d\n",alarm(10));
    getchar();
    printf("alarm(5)返回%d\n",alarm(5));
    pause();//阻塞进程,等待信号
    return 0;
}信号集


[*]多个信号构成的信号聚集谓之信号集
[*]体系内核用sigset_t范例表现信号集
[*]在<signal.h>中又被界说为 typedef __sigset_t sigset_t;
[*]在<sigset.h>中有如下范例界说

[*]#define _SIGSET_NWORDS(1024/(8*sizeof (unsigned long int)))
[*]typedef struct {

[*]        unsigned long int val[ _SIGSET_NWORDS];
[*]} __sigset_t;


[*]sigset_t范例是一个结构体,但该结构体中只有一个成员,是一个包罗32个元素的整数数组(针对32位体系而言)
[*]岂论是32位体系照旧64体系,对于sigset_t如许的一个结构体变量都是128个字节巨细即1024个比特位
 sigfillset函数

#include <signal.h>
int sigfillset (sigset t* sigset);
功能:填满信号集,即将信号集的全部信号位置1
参数:sigset 信号集
返回值:乐成返回0,失败返回-1 
 sigemptyset函数

#include <signal.h>
int sigemptyset (sigset t* sigset);
功能:清空信号集,即将信号集的全部信号位清0
参数:sigset 信号集
返回值:乐成返回0,失败返回-1 
 sigaddset函数

#include <signal.h>
int sigaddset (sigset t* sigset, int signum);
功能:参加信号,即将信号会合与指定信号编号对应的信号位置1
参数:sigset 信号集
        signum:信号编号
返回值:乐成返回0,失败返回-1 
 sigdelset函数

#include <signal.h>
int sigdelset (sigset_t*sigset, int signum);
功能:删除信号,即将信号会合与指定信号编号对应的信号位清0
参数:sigset 信号集
        signum:信号编号
返回值:乐成返回0,失败返回-1 
 sigismember函数

#include <signal.h>
int sigismember (const sigset_t*sigset, int signum);
功能:判断信号会合是否有某信号,即查抄信号会合与指定信号编号对应的信号位是否为1
参数:sigset 信号集
        signum:信号编号
返回值:有则返回1,没有返回0,失败返回-1
 代码演示



#include<stdio.h>
#include<signal.h>

//打印一个字节的8位内容
void printb(char byte){
    for(int i = 0; i < 8; i++){
      printf("%d",(byte & 1 << 7 - i) ? 1 : 0);   
    }
    printf(" ");
    return ;
}
//把一块存储区所有字节比特位都打印出来
void printm(void *buf, size_t size){
    for(int i = 0; i < size; i++){
      printb(((char *)buf));
      if((i + 1) % 8 == 0){
            printf("\n");
      }   
    }
}
int main(){

    //信号集
    sigset_t set;
    //填满信号集
    sigfillset(&set);
    printm(&set,sizeof(set));
    //清空信号集
    sigemptyset(&set);
    printm(&set,sizeof(set));
    //添加一个信号到信号集
    sigaddset(&set,SIGINT);
    printm(&set,sizeof(set));
    //删除一个信号
    sigdelset(&set,SIGINT);
    printm(&set,sizeof(set));
    //判断一个信号是否在信号集中
    printf("信号集中%s2号信号\n",sigismember(&set,SIGINT) ? "有" : "无");
    return 0;
   
}实行效果 


11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111110 01111111 11111111 11111111 11111111
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000010
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
信号集中无2号信号
+ Done                     "/usr/bin/gdb" --interpreter=mi --tty=${DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-ai4ciolt.fpe" 1>"/tmp/Microsoft-MIEngine-Out-cd41dqpd.34f"
day06$ 信号屏蔽

递送、未决与掩码


[*]当信号产生时,体系内核会在其维护的历程表中,为特定的历程设置一个与该信号相对应的标志位,这个过程就叫做递送(delivery)
[*]信号从产生到完成递送之间存在肯定的时间隔断,处于这段时间隔断中的信号状态称为未决(pending)
[*]每个历程都有一个信号掩码(sig币mask),它实际上是一个信号集,位于该信号会合的信号一旦产生,并不会被递送给相应的历程,而是会被壅闭(block)在未决状态
[*]在信号处理处罚函数实行期间,这个正在被处理处罚的信号总是处于信号掩码中,如直到上一个针对该信号的处理处罚过程竣事以结果又有该信号产生,则会被壅闭,才会被递送
[*]当历程正在实行类似更新数据库如许的敏感任务时,大概不盼望被某些信号运停止。这时可以通过信号掩码暂时屏蔽而非忽略掉这些信号,使其一旦产生即被壅闭于未决状态,带特定任务完成后后,再回过头来处理处罚这些信号
可靠和不可靠信号的屏蔽


[*]对于可靠信号,通过sigprocmask函数设置信号掩码以后,每种被屏蔽信号中的每个信号都会被壅闭,并按先后序次列队,一旦排除屏蔽,这些信号会被依次递送
[*]对于不可靠信号,通过sigprocmask函数设置信号掩码以后,每种被屏蔽信号中只有第一个会被壅闭,并在排除屏蔽后被递送,别的的则全部丢失

#include <signal.h>
int sigprocmask (int how, const sigset_t*sigset,sigset_t* oldset);
功能:设置调用历程的信号掩码
参数:how:修改信号掩码的方式,可取以下值
                SIG_BLOCK        -将sigset中的信号参加当前信号掩码
                SIG_UNBLOCK   -从当前信号掩码中删除sigset中的信号
                SIG_SETMASK   -把sigset设置成当前信号掩码
sigset:信号集,取NULL则忽略此参数
oldset:输出原信号掩码,取NULL则忽略此参数
返回值:乐成返回0,失败返回-1
 代码演示(可以将解释内容与对应内容更换以观察可靠信号与不可靠信号的区别)


//屏蔽信号集
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<sys/wait.h>
//信号处理函数
void sigfun(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
    return;
}
//假装执行数据库更新操作
void updatedb(void){
    for(int i = 0;i < 5;i++){
      printf("%d进程:正在执行更新第%d条数据...\n",getpid(),i+1);
      sleep(1);
    }
    return;
   
}
int main(){
    //父进程对2号信号进行捕获处理
    int signum = 50/*SIGINT*/;
    if(signal(signum,sigfun) == SIG_ERR){
      perror("signal");
      return -1;
    }
    //屏蔽2号信号
    printf("%d进程:屏蔽d号信号\n",getpid(),signum);
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set,signum);
    sigset_t oldset;
    if(sigprocmask(SIG_SETMASK,&set,&oldset) == -1){
      perror("sigprocmask");
      return -1;
    }
    //创建子进程
    pid_t pid = fork();
    if(pid == -1){
      perror("fork");
      return -1;
    }
    //子进程向父进程发送2号信号
    if(pid == 0){
      for(int i = 0;i < 5;i++){
            printf("%d进程:向父进程发送%d号信号\n",getpid(),signum);
            if(kill(getppid(),signum) == -1){
                perror("kill");
                return -1;
            }
      }
      return 0;
    }
    //父进程假装执行数据库更新操作
    updatedb();
    //解除父进程对2号信号的屏蔽
    printf("%d进程:解除对%d号信号的屏蔽\n",getpid(),signum);
    if(sigprocmask(SIG_SETMASK,&oldset,NULL) == -1){
      perror("sigprocmask");
      return -1;
    }
    //父进程收尸
    if(waitpid(pid,NULL,0) == -1){
      perror("waitpid");
      return -1;
    }
    return 0;
}实行效果1(不可靠信号) 


day06$./sigprocmask
16029进程:屏蔽d号信号
16029进程:正在执行更新第1条数据...
16030进程:向父进程发送2号信号
16030进程:向父进程发送2号信号
16030进程:向父进程发送2号信号
16030进程:向父进程发送2号信号
16030进程:向父进程发送2号信号
16029进程:正在执行更新第2条数据...
16029进程:正在执行更新第3条数据...
16029进程:正在执行更新第4条数据...
16029进程:正在执行更新第5条数据...
16029进程:解除对2号信号的屏蔽
16029进程:捕获到2号信号实行效果2(可靠信号)


day06$./sigprocmask
15075进程:屏蔽d号信号
15075进程:正在执行更新第1条数据...
15076进程:向父进程发送50号信号
15076进程:向父进程发送50号信号
15076进程:向父进程发送50号信号
15076进程:向父进程发送50号信号
15076进程:向父进程发送50号信号
15075进程:正在执行更新第2条数据...
15075进程:正在执行更新第3条数据...
15075进程:正在执行更新第4条数据...
15075进程:正在执行更新第5条数据...
15075进程:解除对50号信号的屏蔽
15075进程:捕获到50号信号
15075进程:捕获到50号信号
15075进程:捕获到50号信号
15075进程:捕获到50号信号
15075进程:捕获到50号信号

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金
页: [1]
查看完整版本: linux信号处理处罚机制根本(下)