linux编程---信号中断处理

信号

linux提供的信号机制是一种进程间异步的通信机制,在实现上是一种软中断。信号可以导致一个正在运行的进程被另一个异步进程中断。


信号的处理流程

产生信号:产生信号有多种说法。一个进程创建一个信号用于发送给另一个进程叫发送一个信号;内核创建一个信号叫生成一个信号;

一个进程向自己发送一个信号叫唤起一个信号

为使某个信号到来时进程能够执行相应的中断服务程序,即设置某信号到来时执行的代码,称为安装中断

如果一个信号被正确发送到一个进程称为信号被递给。

如果一个信号的递送导致一段处理程序被执行,称为该信号被捕捉。

如果一个信号被发送并且还没有引起任何动作(一般是对应进程阻塞了此信号),称为信号处于等待状态。


产生信号


1 kill产生一个信号

kill(getpid(), sig);

2 raise自举一个信号

int raise(int sig);

3  alarm定时

 #include <unistd.h>
 unsigned int alarm(unsigned int seconds);

4 ualarm定时

useconds_t ualarm(useconds_t usecs, useconds_t interval);


信号处理与signal安装信号

1.信号处理办法

(1)忽略此信号

大多数信号都可以这样处理。除了sigkill和sigstop。

(2)捕捉信号

通知内核在某种信号发生时调用一个用户函数。在用户函数中,如果需要按用户希望执行这种事件进行的处理,即需要安装此信号。

(3)执行系统默认操作。

2.signal安装信号

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);


2 sigaction安装信号


   #include <signal.h>


    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

使用例子

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>

void myhandler(int sig);

int main()
{
        struct sigaction act,oact;
        act.sa_handler = myhandler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGUSR1,&act,&oact);

        while(1)
        {
                printf("hello world\n");
                pause();
        }
}

void myhandler(int sig)
{
        printf("i get signal %d\n",sig);
}


信号集与屏蔽信号

中断可以被屏蔽(阻塞)(部分硬件中断则必须立即处理,例如复位中断),因此,linux的信号是可以屏蔽,即阻塞信号。

(1)清空信号集

 int sigemptyset(sigset_t *set);

(2)完全填空信号集

int sigfillset(sigset_t *set);

(3)添加信号到信号集中

int sigaddset(sigset_t *set, int signum);

(4)从信号集中删除某个信号

int sigdelset(sigset_t *set, int signum);

(5)检测信号是否在信号集中

int sigismember(const sigset_t *set, int signum);


//将阻塞的信号添加到set中

 int sigpending(sigset_t *set);


//设置或获取当前进程阻塞的信号集

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

第1个参数

#define SIG_BLOCK 0

#define SIG_UNBLOCK 1

#define SIG_SETMASK 2

SIG_BLOCK 将第2个参数所描述的集合添加到当前进程阻塞的信号集中。

SIG_UNBLOCK 将第2个参数所描述的集合从当前进程阻塞的信号集中删除。

SIG_SETMASK 无论之前的阻塞信号,设置当前进程阻塞的集合为第2个参数描述的对象。

如果set是空指针,则参数how的值没有意义,且不会更改进程的阻塞信号集,因此该调用可用于查询当前受阻塞的信号 。


函数使用示例


#include<stdio.h>
#include<signal.h>
#include<stdlib.h>

static void sig_quit(int);

int main(int argc,char* argv[])
{
        sigset_t newmask,oldmask,pendmask;

        if(signal(SIGQUIT,sig_quit) == SIG_ERR)
        {
                perror("signal");
                exit(-1);
        }

        printf("install sig_quit\n");

        sleep(10);
        sigemptyset(&newmask);
        sigaddset(&newmask,SIGQUIT);

        if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)
        {
                perror("signalmask ");
                exit(-1);
        }

        printf("block sigquit,wait 15 second...\n");

        sleep(15);

        if(sigpending(&pendmask) < 0)
        {
                perror("sigpending ");
                exit(-1);
        }

        if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)
        {
                perror("sigprocmask ");
                exit(-1);
        }
        printf("sigquit unblocked\n");
        sleep(10);

        return 0;
}

static void sig_quit(int signo)
{
        printf("caught sigquit,the process will quit\n");
        if(signal(SIGQUIT,SIG_DFL) == SIG_ERR) //重新设置
        {
                perror("signal ");
                exit(-1);
        }
}



//等待信号 使当前进程处于等待状态,直到当前进程阻塞信号外任意一个信号出现。

int pause(void);


//将调用进程阻塞的信号集替换为其参数值,然后挂起该线程,直到传递一个非指定集合中信号为止。

int sigsuspend(const sigset_t *mask);


针对sa_mask成员测试应用代码

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>

int output(sigset_t set)
{
    printf("set.val[0]=%x\n",set.__val[0]);
}

void handler(int sig)
{
    int i;
    sigset_t sysset;
    printf("\nin handler sig=%d\n",sig);
    sigprocmask(SIG_SETMASK,NULL,&sysset);
    output(sysset);
    printf("return\n");
}

int main()
{
    struct sigaction act;
    sigset_t set,sysset,newset;
    sigemptyset(&set);
    sigemptyset(&newset);

    //分别加入不同值
    sigaddset(&set,SIGUSR1);
    sigaddset(&newset,SIGUSR2);
    
    printf("\nadd SIGUSR1,the value of set:");
    output(set);
    
    printf("\nadd SIGUSR2,the value of set:");
    output(newset);

    printf("\nafter set proc block set,and then read to sysset\n");
    //设置阻塞值
    sigprocmask(SIG_SETMASK,&set,NULL);
    //读配置
    sigprocmask(SIG_SETMASK,NULL,&sysset);
    output(sysset);
    
    printf("install SIGALRM,and the act.sa_mask is newset(SIGUSR2)\n");
    act.sa_handler = handler;
    act.sa_flags = 0;
    act.sa_mask = newset;
    //安装信号
    sigaction(SIGALRM,&act,NULL);
    //等待信号
    pause();
    
    printf("after exec ISR\n");
    sigemptyset(&sysset);
    //读配置
    sigprocmask(SIG_SETMASK,NULL,&sysset);
    output(sysset);
}



信号应用示例

创建两个进程,父进程执行复制,子进程发送信号给父进程,查询复制进度。

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>


int count;
int file_size;
//处理alarm信号
void sig_alarm(int arg);
//处理普通信号sigusr1
void sig_usr(int arg);

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\n");
        return -1;
    }
    //只读方式打开源文件
    if((fd_src = open(argv[1],O_RDONLY)) == -1)
    {
        perror("open file src");
        exit(-1);
    }
    //获取文件长度
    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_des");
        exit(-1);
    }
    //创建子进程
    if((pid=fork()) == -1)
    {
        perror("fork");
        exit(-1);
    }
    //父进程
    else if(pid > 0)
    {
        //安装信号
        signal(SIGUSR1,sig_usr);
        do
        {
            memset(buf,'\0',128);
            if((i=read(fd_src,buf,1)) == -1)
            {
                perror("read");
                exit(-1);
            }
            else if(i == 0)
            {
                kill(pid,SIGINT);
                break;
            }
            else
            {
                if(write(fd_des,buf,i) == -1)
                {
                    perror("write");
                    exit(-1);                    
                }
                count += i;
            }
        }
        while(i != 0);
        //等待子进程退出,防止僵死进程
        wait(pid,NULL,0);
        exit(0);
    }
    //子进程
    else if(pid == 0)
    {
        usleep(2);
        //安装信号
        signal(SIGALRM,sig_alarm);
        ualarm(1,1);
        //一直执行
        while(1){;}
        exit(0);
    }    
}

void sig_alarm(int arg)
{
    //向父进程发送sigalarm
    kill(getppid(),SIGUSR1);
}

void sig_usr(int arg)
{
    float i;
    i = (float)count / (float) file_size;
    printf("cureent over:%0.0f%%\n",i*100);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值