【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)的没有区别??按理说时间间隔应该变长啊?

原文地址:https://www.cnblogs.com/dplearning/p/4684640.html