栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【无标题】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【无标题】

关于Linux信号的简单说明、使用、编码
    • 1. 信号的产生情况
    • 2.信号的处理方式
    • 3. 与信号相关的系统调用
      • 3.1 向其他进程发送信号(kill)
      • 3.2 设置信号的处理方式(sigaction)
      • 3.3 检测或者更改信号屏蔽字
      • 3.4 检查是否有挂起信号
      • 3.5 使用signal设置信号处理程序
    • 4. 示例程序

    很久没有发文章了,最近想自学一下linux的多进程通信,并做了一些简单的学习笔记,来分享我目前对
多进程微薄的理解。
1. 信号的产生情况
序号产生情况
1硬件产生(非法访问内存、除0操作)
2软件触发(定时器)
3用户终端产生(Ctrl+C)
4用户shell发送kill命令
5同一所有者的进程之间传输信号,或者root用户向进程传输信号
2.信号的处理方式
序号处理方式
1忽略(有些信号不可以忽略,如SIGSTOP)
2默认操作
3用户自定义操作
3. 与信号相关的系统调用
序号系统调用方式
1向其他进程发送信号
2改变默认信号处理方式
3阻塞信号掩模
4检查是否有挂起信号(信号被阻塞)
3.1 向其他进程发送信号(kill)
#include 
#include 

int kill(pid_t pid, int sig);
// pid>0,向pid进程发送信号
// pid=0,向同进程组的其他进程发信号
// pid=-1,向所有有权发送信号的进程发送
// pid<-1,向pid进程组发送信号
// 返回值:0表示成功,-1表示失败,失败时,可以在errno得到错误码
3.2 设置信号的处理方式(sigaction)
#include 

int sigaction(int signum, const struct sigaction *act, const struct sigaction *old);
// signum表示要操作的信号(除了SIGKILL SIGSTOP)
// act为要执行的处理方式
// old为以前的处理方式
struct sigaction
{
    void (*sa_handler)(int); // 默认的处理函数
    void (*sa_sigaction)(int, siginfo_t *, void *); // 当sa_flag包含SA_SIGINFO时,信号处理使用的函数
    sigset_t sa_mask; // 处理函数执行期间需要屏蔽的信号
    int sa_flags; // 指定信号处理行为
    void (*sa_restorer)(void); // 废弃
};
3.3 检测或者更改信号屏蔽字
#include 
int sigpromask(int how, const sigset_t *set, const sigset_t *oldset);
// how: 有三种值,SIG_BLOCK加入信号到进程屏蔽;SIG_UNBLOCK从信号屏蔽中将信号删除;SIG_SETMASK将set值设置为新的进程屏蔽
// set:指向信号集的指针,为NULL时,该函数通过oldset检测当前的设置值
// 返回值:0成功;1失败
3.4 检查是否有挂起信号
// 我理解的挂起是“屏蔽”的意思,可能不太准确
#include 
int sigpending(sigset_t *set);
// 返回值:0成功
3.5 使用signal设置信号处理程序
// signal信号是ANSI C标准的设置信号处理方式的函数,功能与3.2中的sigaction一样,但后者是POSIX标准的
#include 
sighandler_t signal(int signum, sighandler_t hander);
// signum:进程号
// handler:信号处理程序,或者是宏SIG_ING(忽略),或者是宏SIG_DEL(系统默认)
4. 示例程序
// 接下来的实例程序展示了3.1~3.4的函数使用方法,我并没有是使用3.5,因为觉得没必要了
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int Operation2ChildPid2(); // 对第二个子进程的操作
int Operation3ChildPid3(); // 对第三个子进程的操作,信号掩模
void ChildPid2SignalAction(int i32SigNum);

int main()
{
    pid_t pidtChild1 = 0; // 第一个子进程的进程号,用来测试kill命令

    if (0 < (pidtChild1 = fork())) // 主进程
    {
        sleep(5);
        int i32Ret = kill(pidtChild1, SIGSTOP); // 向子进程发送停止信号
        
        if (i32Ret != 0)
        {
            std::cout << "向子进程1发送信号失败" << std::endl;
            exit(EXIT_FAILURE);
        }
        else
        {
            std::cout << "向子进程1发送信号成功" << std::endl;
            i32Ret = Operation2ChildPid2(); // 操作第2个子进程,第二个子进程注册USR1/2两个命令,观察向其发送USR1/2后是佛可以接受成功
            if (EXIT_SUCCESS == i32Ret)
            {
                std::cout << "对子进程2的sigaction测试成功" << std::endl;
                i32Ret = Operation3ChildPid3(); // 操作第3个子进程,测试信号掩模和sigpending
                if (EXIT_SUCCESS == i32Ret)
                {
                    std::cout << "对子进程3的sigaction测试成功" << std::endl;
                }
                else
                {
                    std::cout << "对子进程3的sigaction测试失败" << std::endl;
                    exit(EXIT_FAILURE);
                }
            }
            else
            {
                std::cout << "对子进程2的sigaction测试失败" << std::endl;
                exit(EXIT_FAILURE);
            }

        }

    }
    else if (0 == pidtChild1) // 子进程
    {
        std::cout << "子进程开启" << std::endl;
        for (int i = 0; i < 10; i++)
        {
            std::cout << "子进程1心跳" << i << std::endl;
            sleep(1);
        }
        std::cout << "子进程执行成功" << std::endl;
    }
    else
    {
        std::cout << "fork child1 failed" << std::endl;
        exit(EXIT_FAILURE);
    }

    return EXIT_SUCCESS;
}

int Operation2ChildPid2()
{
    pid_t pidtChild2 = 0;

    if (0 < (pidtChild2 = fork()))
    {
        sleep(5);
        int i32Ret = kill(pidtChild2, SIGUSR1);
        if (i32Ret != 0)
        {
            std::cout << "向子进程2发送USR1信号失败" << std::endl;
            return EXIT_FAILURE;
        }
        else
        {
            i32Ret = 1;
            int i32Ret = kill(pidtChild2, SIGUSR2);
            if (i32Ret != 0)
            {
                std::cout << "向子进程2发送USR2信号失败" << std::endl;
                return EXIT_FAILURE;
            }
            else
            {
                ;
            }
        }
        sleep(7);
    }
    else if (0 == pidtChild2)
    {
        // 子进村注册信号处理函数
        struct sigaction structSigaction;
        structSigaction.sa_flags = SA_RESTART; // 让子进程在处理信号后,继续返回执行信号来时的程序
        structSigaction.sa_handler = ChildPid2SignalAction;
        sigaction(SIGUSR1, &structSigaction, NULL);
        sigaction(SIGUSR2, &structSigaction, NULL);
        
        for (int i = 0; i < 10; i++)
        {
            std::cout << "子进程2心跳" << i << std::endl;
            sleep(1);
        }
    }
    
    return EXIT_SUCCESS;
}
void ChildPid2SignalAction(int i32SigNum)
{
    // 子进程2
    if (SIGUSR1 == i32SigNum)
    {
        std::cout << "子进程2收到USR1信号" << std::endl;
    }
    else if (SIGUSR2 == i32SigNum)
    {
        std::cout << "子进程2收到USR2信号" << std::endl;
    }
    else
    {
        std::cout << "子进村2收到未知信号" << std::endl;
    }

    return;
}
int Operation3ChildPid3()
{
    pid_t pidtChild3 = 0;

    if (0 < (pidtChild3 = fork()))
    {
        sleep(1);
        for (int i = 0; i < 20; i++)
        {
            // 每1秒就发送一个USR1信号
            int i32Ret = kill(pidtChild3, SIGUSR1); // 3秒后向子进程3发送信号
            if (EXIT_SUCCESS == i32Ret)
            {
                std::cout << "向子进程3发送命令成功" << std::endl;
            }
            else
            {
                std::cout << "向子进程3发送命令失败" << std::endl;
            }
            sleep(1);
        }

        sleep(20); // 等待子进程3结束
    }
    else if (0 == pidtChild3)
    {
        // 先注册一个信号的自定义处理
        struct sigaction sigactionUSER1; 
        memset(&sigactionUSER1.sa_mask, 0, sizeof(sigactionUSER1.sa_mask)); // 清空信号处理期间需要屏蔽的信号
        sigactionUSER1.sa_handler = ChildPid2SignalAction; // 就拿子进程2的处理函数来处理吧
        sigactionUSER1.sa_flags = SA_RESTART; // 标记处理函数要使用sa_handler,并且处理完信号后,恢复子进程运行
        sigaction(SIGUSR1, &sigactionUSER1, NULL); // 注册对SIGUSR1的处理函数

        sigset_t sigsetNew, sigsetOld; 
        sigemptyset(&sigsetNew); // 用于设置的新sigset
        sigemptyset(&sigsetOld); // 用于保存的sigset
        sigaddset(&sigsetNew, SIGUSR1); // 需要屏蔽的信号

        sigprocmask(SIG_BLOCK, &sigsetNew, &sigsetOld); // 屏蔽SIGUSR1
        
        for (int i = 0; i < 20; i++)
        {
            std::cout << "子进程3心跳" << i << std::endl;
            if (9 == i)
            {
                sigset_t sigsetSigpending; // 用于提取阻塞信号
                sigpending(&sigsetSigpending);
                if (sigismember(&sigsetSigpending, SIGUSR1))
                {
                    std::cout << "检测到阻塞信号" << std::endl;
                }
                else
                {
                    std::cout << "未检测到阻塞信号" << std::endl;
                }
                sigprocmask(SIG_SETMASK, &sigsetOld, NULL); // 恢复默认阻塞,也就是不阻塞SIGUSR1信号
            }
            sleep(1);
        }
    }
    else
    {
        std::cout << "子进程3创建失败" << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/942611.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号