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

信号
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);
}

猜你喜欢

转载自blog.csdn.net/yinhua405/article/details/77558551