您的位置:首页 > 运维架构 > Linux

linux---编程---进程通信---信号

2017-08-25 10:06 316 查看
信号

linux提供的信号机制是一种进程间异步的通信机制,在实现上是一种软中断。

信号可以导致一个正在运行的进程被另一个进程异步进程中断,转而处理某一个突发事件。

异步事件是不可预见的,只能通过某些特定的方式来预防,或者说,

当该异步事件到来时,根据原来的设定完成相应的操作。

信号中断处理相关的术语

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

内核创建一个信号叫生成一个信号;一个进程向自己发送一个信号叫唤起一个信号。

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

称为安装中断。

(3)如果一个信号被正确发送到一个进程称为该信号被递送。

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

(5)如果一个信号被发送并且还没有引起任何动作(一般是对应进程阻塞了此信号),

称为这个信号处于等待状态。

信号处理办法

(1)忽略此信号。(2)捕捉信号。(3)执行系统默认操作。

signal安装信号

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

#define SIG_ERR /* return error*/

#define SIG_DFL /* default action*/

#define SIG_IGN /* ignore signal*/

sigaction安装信号

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 got signal : %d\n",sig);

}

             

信号集与屏蔽信号

信号忽略:系统仍然传递该信号,只是相应进程对该信号不作任何处理而已。

信号阻塞:系统不传递该信号,显示该进程无法接收到该信号,直到进程的信号集发生改变。

清空信号集

int sigemptyset(sigset_t *set);

完全填空信号集(阻塞所有信号)

int sigfillset(sigset_t *set);

添加信号到信号集中

int sigaddset(sigset_t *set, int signum);

从信号集中删除某个信号

int sigdelset(sigset_t *set, int signum);

检测信号是否在信号集中

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

设置和获取进程阻塞

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

程序示例

程序安装SIGUSR1,阻塞SIGUSR2

#include<stdio.h>

#include<signal.h>

#include<stdlib.h>

static void sig(int);

int main(int argc,char* argv[])

{

    sigset_t newmask,oldmask,pendmask;

    if(signal(SIGUSR1,sig) == SIG_ERR)

    {

        perror("signal");

        exit(-1);

    }

    sigemptyset(&newmask);

    sigaddset(&newmask,SIGUSR2);

    

    if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)

    {

        perror("signalmask ");

        exit(-1);

    }

    

    while(1);

    return 0;

}

static void sig(int signo)

{

    printf("caught signo is %d,the process will quit\n",signo);

}

等待信号

pause函数用来等待除任意信号

用法示例:

#include<stdio.h>

#include<unistd.h>

#include<signal.h>

void handle()

{

        printf("deal with...\n");

}

int main()

{

        printf("begin...\n");

        signal(SIGINT,handle);

        pause();

        printf("end...\n");

        return 0;

}

而sigsuspend函数可以用来等待除指定信号(由其参数指定)外的任意信号

用法程序,其功能等效于pause

#include<stdio.h>

#include<unistd.h>

#include<signal.h>

void handle()

{

        printf("deal with...\n");

}

int main()

{

        printf("begin...\n");

        sigset_t sigmask;

        sigemptyset(&sigmask);

        signal(SIGINT,handle);

        sigsuspend(&sigmask);

        printf("end...\n");

        return 0;

}

程序示例,功能屏蔽设置的信号。

#include<stdio.h>

#include<unistd.h>

#include<signal.h>

void handle()

{

        printf("deal with...\n");

}

int main()

{

        printf("begin...\n");

        sigset_t sigmask;

        sigemptyset(&sigmask);

        sigaddset(&sigmask,SIGINT);

        signal(SIGINT,handle);

        sigsuspend(&sigmask);

        printf("end...\n");

        return 0;

}

程序示例:

功能 sigprocmask函数阻塞信号,sigsuspend函数清空阻塞

#include<stdio.h>

#include<unistd.h>

#include<signal.h>

void handle()

{

        printf("deal with...\n");

}

int main()

{

        printf("begin...\n");

        sigset_t sigmask;

        sigset_t sigmask2;

        sigemptyset(&sigmask);

        sigemptyset(&sigmask2);

        sigaddset(&sigmask2,SIGINT);

        signal(SIGINT,handle);

        sigprocmask(SIG_BLOCK,&sigmask2,0);

        int i;

        for( i =0;i<5;i++)

        {

                printf("run...\n");

                sleep(4);

                printf("run  end...\n");

                sigsuspend(&sigmask);

                printf("run again...\n");

                sleep(4);

                printf("end again ...\n");

        }

        printf("end...\n");

        return 0;

}

程序示例

父进程执行文件拷贝,若收到子进程信号,则打印拷贝进度

子进程每隔固定时间,发送信号给父进程

#include<stdio.h>

#include<fcntl.h>

#include<unistd.h>

#include<stdlib.h>

#include<string.h>

#include<signal.h>

int count;

int file_size;

void sig_alarm(int arg);

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)

{

    kill(getppid(),SIGUSR1);

}

void sig_usr(int arg)

{

    float i;

    i = (float)count / (float) file_size;

    printf("cureent over:%0.0f%%\n",i*100);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: