Linux进程间通讯 --信号

 

1.概念

1.信号是软件终端机制一种模拟,只是一种异步通讯的方式。

2.信号时可以直接用户空间进程跟内核进程进行交互,内核进程可以通过信号通知用户空间发生那些系统事件。

3.如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被 取消时才被传递给进程。

 


 

2.用户进程对信号的相应方式

1)忽略信号:对信号不做任何处理,但是有两个信号不能忽略(SIGKILL 9和SIGSTOP 17

2)捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数。

3)执行取胜操作:Linux对每种信号都规定了默认操作

 

3.信号类型

SIGHUP 1 A 终端挂起或者控制进程终止
SIGINT 2 A 键盘中断(如break键被按下)
SIGQU99v 3 C 键盘的退出键被按下
SIGILL 4 C 非法指令
SIGABRT 6 C 由abort(3)发出的退出指令
SIGFPE 8 C 浮点异常
SIGKILL 9 AEF Kill信号
SIGSEGV 11 C 无效的内存引用
SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道
SIGALRM 14 A 由alarm(2)发出的信号
SIGTERM 15 A 终止信号
SIGUSR1 30,10,16 A 用户自定义信号1
SIGUSR2 31,12,17 A 用户自定义信号2
SIGCHLD 20,17,18 B 子进程结束信号
SIGCONT 19,18,25 进程继续(曾被停止的进程)
SIGSTOP 17,19,23 DEF 终止进程
SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键
SIGTTIN 21,21,26 D 后台进程企图从控制终端读
SIGTTOU 22,22,27 D 后台进程企图从控制终端写

4.相关函数

int kill(pid_t pid,int sig)
功能信号发送
参数输入参数pid指定进程
 sig要发送的信号
 返回值int

成功:0

失败:-1

 

 

 

 

 

 

int raise(int sig)
功能进程向自己发送信号
参数输入参数sig信号
 返回值int

成功:0

失败:-1

 

 

 

 

 

unsigned int alarm(unsigned int seconds)
功能在进程中设置一个定时器
参数输入参数seconds定时时间,单位为秒
 返回值unsigned int如果调用此函数,进程中已经设置了闹钟时间,则返回上个闹钟时间的剩余时间,否则返回为0
注意:一个进程只能有一个闹钟时间。如果再调用alarm时已设置过闹钟时间,则之前的闹钟时间被新值所替代

 

 

 

 

 

 

 

 

 

int pause(void)
功能用于将调用进程挂起直到收到信号为止

 

 

 

void(*signal(int signum,void (*handler)(int)))(int)
功能信号处理函数
参数输入参数signum要处理的信号,不能处理SIGKILL和SIGSTOP
  handler自定义的信号处理函数指针
 返回值  

 

 

 

 

 

 

void abort(void)
功能给自己发送异常终止信号(SIGABRT )

 

 

 

Demo

下面用demo举例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(void){
    printf("%d\r\n",alarm(2));
    sleep(2);
    return 0;
}

运行结果是:

yates@yates-virtual-machine:~/test/code$ ./signal 
0
Alarm clock

过两秒后,出现Alarm Clock 这句话。说明定时器设置成功

如果在第二次设置定时器呢,会打印什么呢?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(void){
    printf("%d\r\n",alarm(7));
    sleep(2);
    while(1){
        printf("%d\r\n",alarm(3));
        sleep(7);
    }
    return 0;
}
yates@yates-virtual-machine:~/test/code$ ./signal 
0
5
Alarm clock

第一次alarm返回值为0,说明第一次设置成功。第二次alarm返回值为5,说明剩余时间为5s

下面我们举个demo说明信号捕捉

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
void handler(int arg){
    printf("handler :%d\r\n",arg);
    // kill(getpid(),9);
}
int main(){
    signal(SIGINT,handler);
    signal(SIGQUIT,handler);
    while(1);
    return 0;
}

执行以上程序

yates@yates-virtual-machine:~/test/code$ ./signal 
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2
^\handler :3
^Chandler :2

当我们键盘输入 ctrl+c 时,返回值为3,如果输入ctrl+\,返回值为2,并且输入 ctrl+c 时,进程不会主动退出。

假如我们要忽略系统信号量呢,怎么办?请看以下demo

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
void handler(int arg){
    printf("handler :%d\r\n",arg);
    // kill(getpid(),9);
}

int main(){
    signal(SIGINT,SIG_IGN);
    signal(SIGQUIT,SIG_IGN);
    while(1);
    return 0;
}

执行以上程序,如果键盘输入 ctrl+c或者 ctrl+\ 时,进程不做处理

yates@yates-virtual-machine:~/test/code$ ./signal 
^\^C^\^C^\^C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

void catch_signal(int sig)
{
    switch(sig)
    {
    case SIGALRM:
        printf("sigalrm have recv !\n");
        alarm(2);
    }
}

int main(int arg,char *args[])
{
    //注册信号
    if(signal(SIGALRM,catch_signal)==SIG_ERR)
    {
        perror("signal error");
        return -1;
    }
    //一个alarm()函数只会发送一次信号
    alarm(1);
    while(1)
    {
        pause();
        printf("accept !\n");
    }

    printf("game over!\n");
    return 0;
}

以上函数执行结果是

yates@yates-virtual-machine:~/test/code$ ./signal 
sigalrm have recv !
accept !
sigalrm have recv !
accept !
sigalrm have recv !
accept !
sigalrm have recv !
accept !

说明SIGALRM可以唤醒函数进程。验证了观点3:如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被 取消时才被传递给进程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值