• 可重入函数与不可重入函数


    1.可重入函数

    可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入 OS 调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区、中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

    常见的不可重入函数有:

    • printf():引用全局变量 stdout
    • malloc():全局内存分配表
    • free():全局内存分配表

    常见的可重入函数有:

    在这里插入图片描述

    #include 
    #include 
    #include 
    #include 
    #include 
    
    int g_mysign = 0;
    
    void muNEfunc(int value)
    {
        g_mysign = value; // 修改全局变量g_mysign的值
    }
    
    // 信号处理函数
    void sig_usr(int signo)
    {
        muNEfunc(22); // 在sig_user这个信号处理函数里调用muNEfunc()
    
        if (signo == SIGUSR1)
        {
            printf("收到了SIGUSR1信号!\n");
        }
        else if (signo == SIGUSR2)
        {
            printf("收到了SIGUSR2信号!\n");
        }
        else
        {
            printf("收到了未捕捉的信号%d!\n", signo);
        }
    }
    
    int main(int argc, char* const* argv)
    {
        // 系统函数,第一个参数是个信号,第二个参数是个函数指针,代表一个针对该信号的捕捉处理函数
        if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR1信号!\n");
        }
    
        if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR2信号!\n");
        }
    
        for (;;)
        {
            sleep(1);
            printf("休息1秒\n");
            
            // 如果刚执行完本行,突然来了个信号,则会导致g_mysign被修改为22,而不是15了
            muNEfunc(15);
    
            printf("g_mysign = %d\n", g_mysign);
        }
    
        printf("再见!\n");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    在写信号处理函数的时候,要注意的事项:

    • 在信号处理函数中,尽量使用简单的语句做简单的事情,尽量不要调用系统函数以免引起麻烦;
    • 如果必须要在信号处理函数中调用一些系统函数,那么要保证在信号处理函数中调用的系统函数一定是可重入的;
    • 如果必须要在信号处理函数中调用那些可能修改 errno 值的可重入的系统函数,那么就得事先备份 errno 值,从信号处理函数返回之前,将 errno 值恢复。
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int g_mysign = 0;
    
    void muNEfunc(int value)
    {
        g_mysign = value; // 修改全局变量g_mysign的值
    }
    
    // 信号处理函数
    void sig_usr(int signo)
    {
        int tmpsign = g_mysign;
    
        muNEfunc(22); // 在sig_user这个信号处理函数里调用muNEfunc()
    
        if (signo == SIGUSR1)
        {
            printf("收到了SIGUSR1信号!\n");
        }
        else if (signo == SIGUSR2)
        {
            printf("收到了SIGUSR2信号!\n");
        }
        else
        {
            printf("收到了未捕捉的信号%d!\n", signo);
        }
        
        g_mysign = tmpsign;
    }
    
    int main(int argc, char* const* argv)
    {
        // 系统函数,第一个参数是个信号,第二个参数是个函数指针,代表一个针对该信号的捕捉处理函数
        if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR1信号!\n");
        }
    
        if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR2信号!\n");
        }
    
        for (;;)
        {
            sleep(1);
            printf("休息1秒\n");
            
            muNEfunc(15);
    
            printf("g_mysign = %d\n", g_mysign);
        }
    
        printf("再见!\n");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    2.不可重入函数的错用演示

    malloc() 不是一个可重入函数。

    #include 
    #include 
    #include 
    #include 
    #include 
    
    // 信号处理函数
    void sig_usr(int signo)
    {
        if (signo == SIGUSR1)
        {
            printf("收到了SIGUSR1信号!\n");
        }
        else if (signo == SIGUSR2)
        {
            printf("收到了SIGUSR2信号!\n");
        }
        else
        {
            printf("收到了未捕捉的信号%d!\n", signo);
        }
    }
    
    int main(int argc, char* const* argv)
    {
        // 系统函数,第一个参数是个信号,第二个参数是个函数指针,代表一个针对该信号的捕捉处理函数
        if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR1信号!\n");
        }
    
        if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR2信号!\n");
        }
    
        for (;;)
        {
            int* p;
            p = (int *)malloc(sizeof(int));
            free(p);
        }
    
        printf("再见!\n");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    在这里插入图片描述

    R+ 表示在前台正在运行中,从上图可以看出,能正常接收和处理信号。

    #include 
    #include 
    #include 
    #include 
    #include 
    
    // 信号处理函数
    void sig_usr(int signo)
    {
        // 不可重入函数malloc()不能用在信号处理函数中
        int* p;
        p = (int *)malloc(sizeof(int));
        free(p);
    
        if (signo == SIGUSR1)
        {
            printf("收到了SIGUSR1信号!\n");
        }
        else if (signo == SIGUSR2)
        {
            printf("收到了SIGUSR2信号!\n");
        }
        else
        {
            printf("收到了未捕捉的信号%d!\n", signo);
        }
    }
    
    int main(int argc, char* const* argv)
    {
        // 系统函数,第一个参数是个信号,第二个参数是个函数指针,代表一个针对该信号的捕捉处理函数
        if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR1信号!\n");
        }
    
        if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        {
            printf("无法捕捉SIGUSR2信号!\n");
        }
    
        for (;;)
        {
            int* p;
            p = (int *)malloc(sizeof(int));
            free(p);
        }
    
        printf("再见!\n");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在这里插入图片描述

    S+ 表示在前台正在休眠中,不能正常接收和处理信号了。从上图可以看到,一旦在信号处理函数中用了不可重入函数,可能导致程序错乱。

    注意:因为兼容性、可靠性等一些历史问题,不建议使用 signal() 函数,建议用 sigaction() 函数代替之。

  • 相关阅读:
    RN操作SQLite数据库的包(sqlite-helper.js)及其使用
    应用开发平台集成工作流系列之15——任务处理设计与实现
    人工智能 PyTorch(一)
    PostgreSQL 连接是否要通过SSL,为什么使用SSL 连接后,业务部门会投诉我?
    C++ 好玩的约瑟夫环(单链表版本)
    Hive函数
    红队专题-开源漏扫-巡风xunfeng源码剖析与应用
    wait 和 notify方法
    计算机网络------TCP协议的可靠传输
    HarmonyOS NEXT应用开发案例——二级联动
  • 原文地址:https://blog.csdn.net/qq_42815188/article/details/127415047