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

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值