信号(二)


1.向另一个进程发送信号

①kill函数

int kill(pid_t pid, int siq)
pid>0将信号sig发给pid进程
pid=0将信号sig发给同组进程
pid=-1将信号sig发送给所有进程,调用者进程有权限发送的每一个进程(除了1号进程之外,还有它自身)
pid<-1将信号sig发送给进程组是pid(绝对值)的每一个进程
例:子进程向父进程(同组进程)发送信号
void  myhandle(int num)
{
    if (num == SIGINT)
    {
        printf("recv signal SIGINT \n");
    }
    else if (num == SIGUSR1)
    {
        printf("recv signal SIGUSR1 \n");
    }
    else
    {
        printf("recv signal id num : %d \n", num);
    }
}


int main(void)
{

    pid_t   pid;
    printf("main ....begin\n");
    
    if (signal(SIGINT, myhandle) == SIG_ERR)
    {
        perror("func signal err\n");
        return 0;
    } 
    if (signal(SIGUSR1, myhandle) == SIG_ERR)
    {
        perror("func signal err\n");
        return 0;
    } 
    
    pid = fork();
    if (pid == -1)
    {
        printf("fork err....\n");
        return 0;
    }
    
    //子进程向父进程发送信号
    //子进程向同组进程发送信号
    if (pid == 0)
    {
        pid = getppid();
        kill(pid, SIGUSR1); //向父进程发信号
        //向进程组发信号
        kill(0, SIGUSR1);      //法一
        //pid = getpgrp();      //法二
        //killpg(pid, SIGUSR1);
        exit(0);
    }
    printf("sleep 函数执行完毕以后返回...\n");
    return 0;
}

②raise函数

给自己发送信号。raise(sig)等价于kill(getpid(), sig);

③sigqueue函数

int sigqueue(pid_t pid, int sig, const union sigval value)价格
功能针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
返回值成功:0,失败:-1
参数
pid指定接收信号的进程id
sig发送的信号
value信号传递的参数
其中第三个参数为union sigval,下面是union sigval的内容:
typedef union sigval
{ 
    int sival_int; 
    void *sival_ptr; 
}sigval_t;      

注:在下面介绍的sigaction()函数的第二个参数结构体参数中,第二个处理器函数siginfo_t参数下有一个sigval_t值。。。

例:两个进程间通过 sigqueue 发送数据
void myHandle_forsigaction(int signum, siginfo_t *s_t, void *p)
{
    int myint = 0;
    printf("recv signum : %d \n", signum);
    myint = s_t->si_value.sival_int;
    printf("%d %d \n", myint, s_t->si_int );
}


int main(int argc, char *argv[])
{
    pid_t   pid;
    int ret = 0;
    
    struct sigaction act;
    act.sa_sigaction = myHandle_forsigaction;
    sigemptyset(&act.sa_mask);
    
    //准备接受额外数据
    act.sa_flags = SA_SIGINFO;

    if (sigaction(SIGINT, &act, NULL) < 0)
        ERR_EXIT("sigaction error");
        
    pid = fork();
    
    if (pid == -1)
    {
        printf("fork err...\n");
        return 0;
    }
    
    if (pid == 0)
    {
        int i = 0;
        /*
        Teacher *t = (Teacher *)malloc(sizeof(Teacher));
        memset(t, 0, sizeof(Teacher));
        strcpy(t->name, "name");
        t->age = 33;
        */
        
        
        /*
         union sigval {
             int   sival_int;
             void *sival_ptr;
         }; */
         
       union sigval  mysigval;
       //mysigval.sival_ptr = (void *)&t;
       mysigval.sival_int = 222;    
    
        //kill(getppid(), SIGINT);
        //带额外数据
        for (i=0; i<10; i++)
        {
            ret  = sigqueue(getppid(), SIGINT, mysigval);
            if (ret != 0)
            {
                printf("sigqueue .....\n");
                exit(0);
            }
            else
            {
                printf("sigqueue...successs\n");
                sleep(2);
            }
        }

    }
    else if (pid > 0)
    {
        for (;;)
            pause();
    }

    return 0;
}

2.改变信号处置

从上一节可知,信号抵达后,有着不同的处理方式,如 `SIG_DFL` :执行默认的方式; `SIG_IGN` :忽略;或者执行信号处理器程序(即程序员自己编写的程序)。
首先介绍如何实现信号处理器程序。

①signal函数

__sighandler_t signal(int signum, __sighandler_t handler);
功能忽略信号、设置信号默认处理或注册一个信号处理函数
返回值返回修改前的handler函数指针
参数
signum信号类型
handler接收到指定信号时将要调用的函数
例1:信号的安装(注册SIGINT)
void handler(int num)
{
    printf("recv num:%d \n", num);  
}


void main()
{
    //注册一个信号
    //SIGINT  是ctrl+c 会产生2号信号。。。 中断应用程序
    signal(SIGINT, handler);
    
    while(1)
    {
        pause();
    }
    
    printf("main...Begin\n");
        
}
例2:信号的恢复
int main(void)
{
    __sighandler_t oldHandle;       //保留原处理信号行为
    printf("main ....begin\n");
    oldHandle = signal(SIGINT, myhandle); 
    if (oldHandle == SIG_ERR)
    {
        perror("func signal err\n");
        return 0;
    } 
    
    printf("if u enter a, reset signal \n");
    while(getchar() != 'a')
    {
        ;
    }

    //键入a以后,信号的恢复 
    //法一:恢复默认函数
    /*
    if (signal(SIGINT, oldHandle) == SIG_ERR)
    {
        perror("func signal err\n");
        return 0;
    }
    */
    //法二:
    if (signal(SIGINT, SIG_DFL) == SIG_ERR)
    {
        perror("func signal err\n");
        return 0;
    }
        
    while(1) ;
    return 0;

}

②sigaction函数

int sigaction(int signum,const struct sigaction act,const struct sigaction old)
功能注册一个信号处理函数
返回值成功:0,失败:-1
参数
signum信号类型
act指向结构sigaction的一个实例的指针
old保存原来对相应信号的处理
第二个参数act包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些信号等等。下面是struct sigaction的内容:
struct sigaction {
    void (*sa_handler)(int);   //信号处理程序一: 不接受额外数据,同signal()的第二个参数
    void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序二:能接受额外数据,和sigqueue配合使用 
    sigset_t sa_mask; //定义一组信号,不允许中断此处处理程序的执行
    int sa_flags; //影响信号的行为   SA_SIGINFO表示能接受数据
    void (*sa_restorer)(void); //废弃
};
由于struct sigaction结构中信号处理程序一与之前在signal中介绍的处理函数相似,所以接下来介绍信号处理程序二的使用。
第二个参数siginfo_t内容如下:
 siginfo_t {
              int      si_signo;  /* Signal number */
              int      si_errno;  /* An errno value */
              int      si_code;   /* Signal code */
              pid_t    si_pid;    /* Sending process ID */
              uid_t    si_uid;    /* Real user ID of sending process */
              int      si_status; /* Exit value or signal */
              clock_t  si_utime;  /* User time consumed */
              clock_t  si_stime;  /* System time consumed */
              sigval_t si_value;  /* Signal value */  
              int      si_int;    /* POSIX.1b signal */
              void *   si_ptr;    /* POSIX.1b signal */
              void *   si_addr;   /* Memory location which caused fault */
              int      si_band;   /* Band event */
              int      si_fd;     /* File descriptor */
            }

注:
①si_code:表示信号来源,对于通过sigqueue()发送的实时信号来说,该字段为SI_QUEUE
②si_value:由进程使用sigqueue()发送信号时在value参数中指定

③signal()与sigaction()

sigaction()是建立信号处理器的首选API,较之signal()可移植性更佳。而往往使用signal()将信号处置设置为SIG_IGN或SIG_DFL。
例:用sigaction模拟signal函数
void handler(int sig)
{
    printf("recv a sig=%d\n", sig); 
}

__sighandler_t my_signal(int sig, __sighandler_t handler)
{
    struct sigaction act;
    struct sigaction oldact;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    if (sigaction(sig, &act, &oldact) < 0)
        return SIG_ERR;

    return oldact.sa_handler;
}

int main(int argc, char *argv[])
{         
    struct sigaction act;
    sigset_t sa_mask;
    
    act.sa_handler = handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);

    //测试信号安装函数
    //sigaction(SIGINT, &act, NULL);
    
    //模拟signal函数
    my_signal(SIGINT, handler);

    for (;;)
    {
        pause();
    }
    return 0;
}

转载于:https://www.cnblogs.com/EngineerZhang/p/9313699.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值