zoukankan      html  css  js  c++  java
  • 【linux高级程序设计】(第十章)Linux异步信号处理机制 3

    信号屏蔽

    信号忽略:系统仍然传递该信号,只是相应的进程不做任何处理

    信号屏蔽:进程不捕获信号,信号处于未决状态,当不再屏蔽信号时可以捕获之前被屏蔽的信号。

    信号集数据结构定义:

    typedef __sigset_t sigset_t;
    #define _SIGSET_NWORDS   (1024 / (8 * sizeof(unsigned long int)))
    typedef struct
    {
        //此结构体占据32 * 32 = 1024 bit 每bit对应一个信号 val[0]0-31位对应常用1-31信号
        unsigned long int __val[_SIGSET_NWORDS];
    }__sigset_t;

    int sigprocmask (int __how, __const sigset_t *__restrict __set, sigset_t * __restrict __oset) :设置屏蔽信号集。成功0,否则-1.

    第一个参数:更改该集的方式

    • SIG_BLOCK : 将第2个参数描述的集合添加到当前进程屏蔽的信号集中
    • SIG_UNBLOCK : 将第2个参数描述的集合从到当前进程屏蔽的信号集中删除
    • SIG_SETMASK : 无论之前屏蔽了哪些信号,设置当前屏蔽集为第2个参数描述的对象。

    如果set是空指针,则how没有意义,不会更改屏蔽信号集,因此可以查询当前屏蔽的信号集合。

    int sigpending (sigset_t * __set) :获取当前未决的信号。成功0,否则-1.

    int sigemptyset (sigset_t * __set) :  清空信号集

    int sigfillset (sigset_t * __set) :将set的所有位都置为1.

    int sigaddset (sigset_t *__set, int __signo) : 添加信号到信号集set

    int sigdelset (sigset_t * __set, int __signo) : 从set中删除信号

    int sigismember (__const sigset_t *__set, int __signo) : 检测信号是否在信号集,是返回1,否则返回0

    int sigisemptyset (__const sigset_t * __set) : 检测信号集是否为空信号集

    int sigandset (sigset_t *__set, __const sigset_t *__left, __const sigset_t *__right) : 用逻辑与的方式将两个信号合并

    int sigorset (sigset_t *__set, __const sigset_t *__left, __const sigset_t *__right) : 用逻辑或的方式将两个信号合并

    当一个信号在处理的过程中,相同的信号会暂时屏蔽,防止信号处理嵌套。

    等待信号

    int pause (void) :等待除了当前屏蔽信号集合外的任意信号

    int sigsuspend (__const sigset_t * __set) :将当前进程屏蔽的信号集替换为其参数所指定的信号集合,直到收到非指定集合中的信号才继续执行

    注意 不能屏蔽SIGKILL和SIGSTOP

    信号应用例子

    功能是复制文件,父进程执行复制操作,如果收到SIGUSR1信号则打印当前复制进度;子进程每隔固定时间向父进程发送SIGUSR1信号,通过SIGALARM

    #include<stdio.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<string.h>
    #include<signal.h>
    #include<stdlib.h>
    int count;  //当前复制大小
    int file_size;   //文件大小
    void sig_alarm(int arg);  //处理alarm信号
    void sig_usr(int sig);   //处理普通信号SIGUSR1
    int main(int argc, char *argv[])
    {
        pid_t pid;
        int i;
        int fd_src, fd_des;
        char buf[128]; //复制操作临时空间
        if(argc != 3)
        {
            printf("check the format:comm src_file des_file
    ");
            return -1;
        }
        if((fd_src = open(argv[1], O_RDONLY)) == -1)
        {
            perror("open file src");
            exit(EXIT_FAILURE);
        }
        file_size = lseek(fd_src, 0, SEEK_END);  //获取资源文件大小
        lseek(fd_src, 0, SEEK_SET);   //重新设置读写位置为文件头
        if((fd_des = open(argv[2], O_RDWR|O_CREAT, 0644)) == -1)
        {
            perror("open fd_fdes");
            exit(EXIT_FAILURE);
        }
        if((pid = fork()) == -1)
        {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        else if(pid > 0)
        {
            signal(SIGUSR1, sig_usr);  //安装信号SIGUSR1
            do
            {
                memset(buf, '', 128);
                if((i = read(fd_src, buf, 1)) == -1)
                {
                    perror("read");
                    exit(EXIT_FAILURE);
                }
                else if(i == 0)  //如果复制完毕,向子进程发送SIGINT信号,终止子进程
                {
                    kill(pid, SIGINT);
                    break;
                }
                else
                {
                    if(write(fd_des, buf, i) == -1)
                    {
                        perror("write");
                        exit(EXIT_FAILURE);
                    }
                    count += i;  //更新已经复制的大小
                }
            }while(i != 0);
            wait(pid, NULL, 0);  //等待子进程退出
            exit(EXIT_SUCCESS);
        }
        else if(pid == 0)
        {
            usleep(1);
            signal(SIGALRM, sig_alarm);  //安装SIGALRM信号
            ualarm(1, 1);
            while(1);
            exit(EXIT_SUCCESS);
        }
    }
    
    void sig_alarm(int arg)
    {
        kill(getppid(), SIGUSR1); //向父进程发送SIGUSR1信号
    }
    void sig_usr(int sig)
    {
        float i;
        i = (float)count/(float)file_size;
        printf("current over : %0.0f%%
    ", i *100);
    }

    功能可以实现,但是奇怪的是ualarm中的数字,即使我改成很大,比如ualarm(100,1000) 信息输出的还是很密集,感觉跟 ualarm(1,1)的没有区别??按理说时间间隔应该变长啊?

  • 相关阅读:
    SPOJ GSS1 ~ 8解题报告 【完整版】
    题解 UVA1659 【帮助小罗拉 Help Little Laura】
    题解 UVA753 【UNIX插头 A Plug for UNIX】
    题解 P3740 【[HAOI2014]贴海报】
    对拍程序
    dut新生大礼包3
    1240C
    DISCO Presents Discovery Channel Code Contest 2020 Qual 题解
    1254C
    1285E
  • 原文地址:https://www.cnblogs.com/dplearning/p/4684640.html
Copyright © 2011-2022 走看看