美文网首页
Unix进程通信:信号

Unix进程通信:信号

作者: FakeCSer爱去网吧 | 来源:发表于2020-02-24 20:57 被阅读0次

信号原理

  • 信号机制:事件促使内核向进程发送信号
  • 事件类型:
    • 键盘按键请求内核产生信号:ctrl+c、ctrl+/等
    • 进程执行出错时,如越界访问,0做除数,整形溢出。内核给进程发信号
    • 一个进程调用kill给另一个进程发信号。
  • 信号机制过程
    信号未决(信号处理之前的状态):事件产生->内核发送信号给指定进程->信号注册(信号进PCB)
    信号递送(信号处理动作):信号被屏蔽/若未被屏蔽,信号从PCB注销->信号处理
  • 信号处理方式
    • 按默认方式处理:man 7 signal可以查看每个信号的默认处理方式
    • 忽略信号,SIGKILL和SIGSTOP不能被忽略
    • 捕捉信号,作出反应
  • 可用于进程间使用信号通信
  • 异步通信机制(约定信号处理机制)
  • shell中用 kill -l 查看信号


  • 信号分类
    • 小于32号为不可靠信号,不支持信号队列。后面为可靠信号,支持信号队列
    • 同步信号:本进程操作产生的信号。异步信号:进程之外的事件引发的信号。
  • 信号的意义见官方信号表
    http://man7.org/linux/man-pages/man7/signal.7.html
    也可在终端输入man 7 signal查看信号详细信息和默认处理方式

信号处理函数API

include <signal.h>
__sighandler_t signal(int signum,__sighandler_t handler)

参数表:
signum:要处理的信号
handler:信号处理函数

  • __sighandler_t的定义:typedef void (*__sighandler_t)(int);
    函数指针:返回值为void,有一个类型为int的参数
    此参数对应三种不同的应对
    • SIG_IGN:忽略
    • SIG_DFL:默认
    • 函数名:用户自己定义的反应函数

返回值:
不为-1:成功
SIG_ERR:出错
示例代码:

#include <signal.h>
#include <stdlib.h>//perror,exit()
#include <unistd.h>//fork(),pause()
#include <sys/wait.h>//wait()
#include <iostream>
using namespace std;
 
void fun(int signal)
{
    cout << "process:"<<getpid()<<"have captured the signal " << endl;
}

int  main()
{
    int pid;
    if( ( pid = fork() ) == -1 )
    {
        perror("fork");
        exit(1);    
    }       

    else if(pid == 0)//son process
    {
        signal(SIGINT,fun);
        //SIGINT:signal from keyboard
        //约定信号处理函数
        
        cout << "waiting for signal" << endl;       
        pause();//挂起等待信号
    }
    else//parent process
    {
        sleep(1);
        kill(pid,SIGINT);//发送信号
        wait(NULL);
    }
}

也可发送信号10(用户自定义信号)来进行进程通信

signal函数存在的问题

  • 信号处理不可靠
    处理结束后需要再次设置监听,所以常用此结构
    void handler(int signo)
    {
      signal(SIGINT,handler);
    ...
    }
    
    这种结构在相应处理完信号到重设监听状态有一段危险时间(虽然很短)
  • 不方便获取当前信号处理方式
  • 无法处理多个信号--无法阻塞信号

其他信号相关api(待更新)

  • sigaction:
    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
    • 当act为空,oldact非空:获取signum当前的处理方式
    • 当act非空,oldact为空:安装信号处理函数
    • 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);
}

一个小例子
通过argv来传送pid和signum
发送端

#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

void main(int argc,char**argv)
{
        pid_t pid;
        pid=(pid_t)atoi(argv[1]);
        int signum;
    signum = atoi(argv[2]);
        union sigval mysigval;
        if(kill(pid,signum)==-1)
                printf("send error\n");
        sleep(2);
}

接收端

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>//atoi
void new_op(int signum)
{
        printf("recieve signumm %d\n",signum);
}

int main(int argc,char**argv)
{
        struct sigaction act;
        sigemptyset(&act.sa_mask);
        act.sa_handler=new_op;
        act.sa_flags=SA_RESETHAND;
        if(sigaction(30,&act,NULL)<0)
        {
                printf("install sigal error\n");
        }
        pid_t pid;         
        pid=getpid();
    printf("pid : %d\n",pid);
    sleep(10);
}
image.png
  • kill:发送信号
  • raise:给自己发信号
  • alarm:计时器
  • pause:挂起(等信号)(pause+alarm = sleep):
  • sigqueue:可以在发信号的时候传参

相关文章

网友评论

      本文标题:Unix进程通信:信号

      本文链接:https://www.haomeiwen.com/subject/cnibqhtx.html