信号编程之信号发送及信号处理函数遇到不可重入函数

来源:互联网 发布:qq老密数据库下载 编辑:程序博客网 时间:2024/06/09 12:49

kill函数

  • 函数原型: Int kill(pid_t pid, int siq)
  • 功能:既可以向自身发送信号,也可以向其他进程发送信号;
  • 参数:
    • pid>0 将信号sig发给pid进程
    • pid=0 将信号sig发给同组进程
    • pid=-1 将信号sig发送给所有进程,调用者进程有权限发送的每一个进程(除了1号进程之外,还有它自身)
    • pid<-1 将信号sig发送给进程组是pid(绝对值)的每一个进程

注意,如果在fork之前安装信号,则子进程可以继承信号。
补充:getpgrp()函数获取进程组pid

sleep函数

函数原型:unsigned int sleep(unsigned int seconds);
功能:让进程睡眠。原理和wait类似,都有可能被其他信号打断!

注意:
1)能被信号打断,然后处理信号函数以后,就不再睡眠了。直接向下执行代码
2)sleep函数的返回值,是剩余的秒数

  • 示例代码:
#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <errno.h>#include <signal.h>#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>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 = getpgrp();        pid = getppid();        //kill(pid, SIGUSR1); //向老爹发信号        kill(0, SIGUSR1); //向进程组发信号        //killpg(pid, SIGUSR1);        exit(0);    }    */    if (pid == 0)    {        pid = getpgrp();        killpg(pid, SIGUSR1);        exit(0);    }    int n = 3;    do     {        printf("父进程开始睡眠\n");        n = sleep(n);        printf("父进程开始唤醒\n");    } while (n > 0);    //sleep(n);    printf("sleep 函数执行完毕以后返回...\n");    return 0;}

raise函数

函数原型: int raise(int sig);
功能:给自己发送信号。raise(sig)等价于kill(getpid(), sig);

kill可以发送信号给其他进程

killpg函数

函数原型:int killpg(int pgrp, int sig);
功能:给进程组发送信号。killpg(pgrp, sig)等价于kill(-pgrp, sig);

sigqueue函数

函数原型:int sigqueue(pid_t pid, int sig, const union sigval value);
函数功能: 给进程发送信号,支持排队,可以附带信息

pause函数

  • 将进程置为可中断睡眠状态。然后它调用内核函数schedule(),使linux进程调度器找到另一个进程来运行。
  • pause使调用者进程挂起,直到一个信号被捕获就返回,不再阻塞调用者进程。

alarm函数

功能:设置一个闹钟延迟发送信号。告诉linux内核n秒以后,发送SIGALRM信号;
函数原型:unsigned int alarm(unsigned int seconds);

注意:该闹钟只是一次有效,如果要重复有效,则需要在信号处理函数里面再次调用alarm函数设置闹钟。

void  myhandle(int num){    printf("recv signal id num : %d \n", num);    alarm(1);}int main(void){    printf("main ....begin\n");    //注册信号处理函数    if (signal(SIGALRM, myhandle) == SIG_ERR)    {        perror("func signal err\n");        return 0;    }     alarm(1);    while(1)     {        pause();        printf("pause return\n");    }    return 0;}

信号处理函数遇上可重入和不可重入函数

  所谓可重入函数是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错。因为进程在收到信号后,就将跳转到信号处理函数去接着执行。--也就是说可重入函数可以被多个进程或者函数同时调用,但不必关心内部数据和全局数据是否会被修改。
  如果信号处理函数中使用了不可重入函数,那么信号处理函数可能会修改原来进程中不应该被修改的数据,这样进程从信号处理函数中返回接着执行时,可能会出现不可预料的后果。不可重入函数在信号处理函数中被视为不安全函数。
  满足下列条件的函数多数是不可再入的:
  (1)使用静态的数据结构,如getlogin(),gmtime(),getgrgid(),getgrnam(),getpwuid()以及getpwnam()等等;
  (2)函数实现时,调用了malloc()或者free()函数
  (3)实现时使用了标准I/O函数的

结论:在信号处理函数中,尽量不使用含有全局变量和静态变量的函数。特别是这个变量在程序中随时可能读写。
man 7 signal 查找可重入函数和不可重入函数。

#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <errno.h>#include <signal.h>typedef struct _Teacher{    int age;    int num;    }Teacher;Teacher g_t;char *p = NULL:void printfGlobTeacher(){    printf("g_t.age:%d \n", g_t.age);//含有全局变量--不可重入--gt一直在改变    printf("g_t.num:%d \n", g_t.num);    //p = malloc(100);//容易引起不可重入}void  myhandle(int num){    printf("recv signal id num : %d \n", num);    printfGlobTeacher();    alarm(1);}int main(void){    Teacher t1, t2;    t1.age = 30;    t1.num = 30;    t2.age = 40;    t2.num = 40;    printf("main ....begin\n");    //注册信号处理函数    if (signal(SIGALRM, myhandle) == SIG_ERR)    {        perror("func signal err\n");        return 0;    }     //间接递归    //myhandle----->alarm=====>myhandle    alarm(1);    while(1)     {        g_t = t1;        g_t = t2;    }    return 0;}
0 0
原创粉丝点击