signal

为信号注册捕获信号后的处理函数

头文件:
    #include <signal.h>
原型:
    typedef void (*sighandler_t)(int); //数据类型,指针类型,数据类型的名字是sighandler_t;
    sighandler_t signal(int signum, sighandler_t handler);
参数:
    int signum:要捕获的信号的值,可以填数值,也可以填对应的宏。例如可以填10,或者SIGUSR1;如果填以下宏:
        SIG_IGN:忽略该信号;
        SIG_DFL:执行默认处理函数;
    sighandler_t handler:handler为函数指针变量,该函数指针指向信号处理函数,信号处理函数的原型: void handler(int sig);
返回值:
    成功,返回设置之前的信号处理函数handler的地址;
    失败,返回SIG_ERR,更新errno;
例程:
    typedef void (*sighadler_t)(int);
    void handler(int sig)
    {  
        printf("成功收到%d号信号\n", sig);
    }
int main(void){
    sighadler_t s = signal(SIGUSR1, handler);
    if(SIG_ERR == s)
    {   
        perror("signal");
        return -1; 
    }   
}

kill

发送信号给指定进程或进程组

头文件:
    #include <sys/types.h>
    #include <signal.h>
原型:
    int kill(pid_t pid, int sig);
参数:
    pid_t pid:指定进程的进程号或所在的进程组
        pid > 0: 发送信号给指定进程号的进程;
        pid == 0: 发送信号给当前进程组下的所有进程;
        pid == -1: 发送信号给系统内的所有权限所能发送到的进程,除了init进程;
        pid < -1: 发送信号给进程组ID为pid的绝对值的所有进程;
    int sig:指定要发送的信号,可以填数值,也可以填宏;
        sig == 0; 没有发送信号,可以用于判断pid进程或者进程组是否存在;
返回值:
    成功,返回0;
    失败,返回-1,更新errno;
例程:
    if(kill(pid, 10) < 0)
    {
        perror("kill");
        return -1;
    }

raise

给自身发送一个信号

头文件:
    #include <signal.h>
原型:
    int raise(int sig);    等同于kill(getpid(), sig);
参数:
    int sig:指定要发送的信号,可以填数值,也可以填宏;
返回值:
    成功,返回0;
    失败,返回非0;

alarm

设置一个定时器,等到时间结束,产生一个 14) SIGALRM 时钟信号

头文件:
    #include <unistd.h>
原型:
    unsigned int alarm(unsigned int seconds);
参数:
    unsigned int seconds:设置定时时间,单位为秒;
        seconds == 0;删除定时器,并且不会产生 SIGALRM 信号;
返回值:
    成功,返回上一个定时器没有走完的秒数;
    失败,返回0,如果没有预先设置定时器;
注意:
    1.alarm是一个非阻塞的函数,会立即返回;
    2.alarm会返回上一次设定后,没有走完的时间,所以一个进程只能设置一个定时器;
    3.alarm(0),会删除定时器,并且不会产生SIGALRM信号;

pause

使进程阻塞,直到进程收到任意信号,并且执行了信号处理函数后结束阻塞

头文件:
    #include <unistd.h>
原型:
    int pause(void);
返回值:
    pause会一直阻塞,直到执行了信号处理函数,并且从信号处理函数返回后,
    pause才会结束阻塞,返回-1,并设置errno为EINTR;

例程:

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

typedef void (*sighandler_t)(int);
void handler(int sig)
{
    printf("Ring......\n");
}

int main(int argc, const char *argv[])
{
    //捕获14号信号
    sighandler_t s = signal(SIGALRM, handler);
    if(s == SIG_ERR)
    {
        perror("signal");
        return -1;
    }

    unsigned int res ;
    res = alarm(3);

    pause();

    return 0;
}

strsignal

打印指定信号的默认处理函数功能

void handler(int signum)
{
    printf("触发%d号信号:%s\n", signum, strsignal(signum));
}头文件:
    #include <string.h>
原型:
    char *strsignal(int sig);
参数:
    int sig:指定要发送的信号,可以填数值,也可以填宏;
返回值:
    返回指定信号的默认处理函数功能的描述字符串,如果信号编号无效,则返回未知信号消息。 
例程:
    void handler(int signum)
    {
        printf("触发%d号信号:%s\n", signum, strsignal(signum));
    }

应用例程1

用信号方式回收僵尸进程

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
typedef void (*sighandler_t)(int);
void handler(int sig)
{
    pid_t pid;
    //非阻塞方式,如果子进程退出,则返回被回收的子进程的pid;如果没有子进程退出,则返回0
    //循环,只要父进程能够收到最后一个信号,就能把前面(信号丢失时)未回收的僵尸进程回收完
    while((pid = waitpid(-1, NULL, WNOHANG)) > 0)
    {
        printf("回收了一个子进程 %d 的资源\n",pid);
    }
}
int main(int argc, const char *argv[])
{
    //注册 SIGCHLD信号
    sighandler_t s;
    s = signal(SIGCHLD, handler);
    if(s == SIG_ERR)
    {
        perror("signal");
        return -1;
    }
    pid_t pid = fork();
    if(pid > 0)
    {
        while(1)
        {
            printf("this is parent....\n");
            sleep(1);
        }
    }
    else if(0 == pid)
    {
        int i = 0;
        for(i=0; i<3; i++)
        {
            printf("this is child\n");
            sleep(1);
        }
        exit(1);
    }
    else
    {
        perror("fork");
        return -1;
    }
    return 0;
}

应用例程2

创建两个没有血缘关系的进程A,B。

  1. A进程拷贝图片的前半部分,拷贝结束后,退出。
  2. 等待A进程拷贝结束后,B进程拷贝后半部分。
  3. 不能使用sleep函数。

提示:使用有名管道,信号,pause函数。

A进程拷贝前半部分

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, const char *argv[])
{
    //创建有名管道
    if(mkfifo("./myfifo",0664) < 0)
    {
        if(errno != EEXIST)
        {
            perror("mkfifo");
            return -1;
        }
    }
    int fd = open("./myfifo",O_RDONLY);
    if(fd < 0)
    {
        perror("open");
    }
    printf("管道创建成功,并打开了读端\n");
    //打开原图
    int picture = open("/home/linux/Pictures/p1.jpg",O_RDONLY);
    int size = lseek(picture,0,SEEK_END);
    lseek(picture,0,SEEK_SET);
    //打开要拷贝的图片
    int picture_copy = open("/home/linux/Pictures/4_6.jpg",O_WRONLY|O_CREAT|O_TRUNC,0664);
    //拷贝一半图片
    int i=0;
    int res;
    for(i=0;i<size/2;i++)
    {
        if(read(picture,&res,1) < 0)
        {
            perror("read");
            return -1;
        }
        if(write(picture_copy,&res,1) < 0)
        {
            perror("write");
            return -1;
        }
    }
    printf("size = %d\n",size);
    printf("size/2 = %d\n",size/2);
    int s1 = lseek(picture,0,SEEK_CUR);
    printf("s1 = %d\n",s1);
    int s2 = lseek(picture_copy,0,SEEK_CUR);
    printf("s2 = %d\n",s2);
    printf("前半部分拷贝完毕\n");
    //传递信号给进程class2
    pid_t pid;
    if(read(fd,&pid,sizeof(pid)) < 0)
    {
        perror("read");
        return -1;
    }
    printf("class2's pid = %d\n",pid);
    if(kill(pid,SIGUSR1) < 0)
    {
        perror("kill");
        return -1;
    }
    printf("信号发送完毕\n");
    return 0;
}

B进程拷贝后半部分

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
int flag = 0;
void handler(int signum)
{
    flag = 1;
    printf("接收到信号%d了\n",signum);
}
int main(int argc, const char *argv[])
{
    //捕获10号信号
    sighandler_t signum = signal(SIGUSR1,handler);
    if(signum == SIG_ERR)
    {
        perror("signal");
        return -1;
    }
    printf("10号信号注册完毕\n");
    //创建有名管道
    if(mkfifo("./myfifo",0664) < 0)
    {
        if(errno != EEXIST)
        {
            perror("mkfifo");
            return -1;
        }
    }
    int fd = open("./myfifo",O_WRONLY);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("管道创建成功,并打开了写端\n");
    //打开原图
    int picture = open("/home/linux/Pictures/p1.jpg",O_RDONLY);
    int size = lseek(picture,0,SEEK_END);
    printf("size = %d\n",size);
    int s1 = lseek(picture,size/2,SEEK_SET);
    printf("s1 = %d\n",s1);
    //打开要拷贝的图片
    int picture_copy = open("/home/linux/Pictures/4_6.jpg",O_WRONLY|O_CREAT|O_TRUNC,0664);
    int s2 = lseek(picture_copy,size/2,SEEK_SET);
    printf("s2 = %d\n",s2);
    //发送pid给管道
    pid_t pid = getpid();
    if(write(fd,&pid,sizeof(pid)) < 0)
    {
        perror("write");
        return -1;
    }
    printf("pid发送完毕\n");
    //阻塞,等待class1拷贝完成信号
    pause();
    //接收到信号,拷贝后半部分图片
    int i;
    int res;
    if(flag)
    {
        printf("size/2 = %d\n",size/2);
        for(i=size/2;i<size;i++)
        {
            if(read(picture,&res,1) < 0)
            {
                perror("read");
                return -1;
            }
            if(write(picture_copy,&res,1) < 0)
            {
                perror("write");
                return -1;
            }
        }
    }
    printf("后半部分拷贝完毕\n");
    return 0;
}

结果

Last modification:2021 年 04 月 13 日 11 : 53 : 51