C语言 系统调用操作内核信号集

  • Post author:
  • Post category:其他


// 、、使用内存映射可以拷贝文件
/*
对原始文件进行内存映射
创建一个新文件
把新文件的数据拷贝映射到内存中
通过内存拷贝将第一个文件的内存映射区拷贝到第二个文件的内存映射区
释放资源
*/

// 匿名映射,不需要文件实体来进行内存映射
// 只能用于有血缘关系的进程间通信
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
// int main()
// {

    /*
// kill函数
// pid》0将信号发送给指定进程
// =0:将信号发送给当前进程组
// =-1:将信号发送给每一个有权限接受这个信号的进程
// 《-1:进程组id的绝对值
// sig,要发送的信号
// kill(getppid(), 9);
// kill(getpid(), 9);
// raise函数,给当前进程发送信号
// sig,要发送的信号,成功返回0,失败返回非0*/
// alarm函数
// 设置定时器,倒计时,当时间为0的时候,会给当前进程发送一个 SIGALARM信号
// 取消定时器,alarm(0)即可
// 返回值是unsigned int,倒计时剩余的时间(上一个alarm剩余的时间)
// SIGALRARM信号默认终止当前进程,每个进程只能设置一个定时器
// int seconds = alarm(5);
// printf("%d\n", seconds);
//  sleep(2);
//  seconds = alarm(3);
// printf("%d\n", seconds);
// while(1){

// }
// 1秒钟电脑能输多少个数?
//无论进程处于什么状态,alarm都会正常计时
// 实际时间=内核时间+用户时间+io消耗的时间
// alarm(1);
// int i =0;
// while(1){
//     printf("%d\n",i++);
// }

// settimeer函数,用于替换alarm函数,且精度比alarm要高很多,
// 参数
// which,定时器以什么时间计时
//     ITIME_REAL: 真实时间,时间到达,就发送SIGALRM
//     ITIME_VIRTUAL;用户时间,时间到达就发送SIGVTALRM
//     ITIMER_PROF:进程在内核状态下消耗的时间
// 过3秒后,每两秒执行一次
// struct itimerval new_value;
// // 设置值
// new_value.it_interval.tv_sec = 2;
// new_value.it_interval.tv_usec =0;
// new_value.it_value.tv_sec=3;
// new_value.it_value.tv_usec=0;
// int ret = setitimer(ITIMER_REAL,&new_value,NULL);
// printf("定时器开始\n");
// if (ret==-1){
//     perror("settimer");
//     exit(0);
// }
// getchar();
// signal捕获信号
// sigkill,sigstop既不能被捕捉也不能被忽略
// signum:要捕捉的信号
// handler:捕捉到信号之后如何处理
//     sig_ign:忽略
//     sig_dfl:使用信号默认的行为
//     回调函数:捕获到信号后执行该函数
// 过3秒后,每两秒执行一次
// 注册信号捕捉函数
//忽略信号
// signal(SIGALRM,SIG_IGN);
//直行信号的默认动作(sig_ALRM结束程序)
// signal(SIGALRM,SIG_DFL);
// void (*sig_handler)(int),这是一个函数指针。返回void,参数int,函数名称:sig_handler
void sig_handler(int num) {
    printf("捕获到了信号:%d\n", num);
    printf("lllllllllllllll]n");
}
int main()
{
//     信号集
//     产生但是还没有被处理的信号被归到未决信号集

//     sigint信号状态被存储在第二个bit位上
//         bit位为1,说明信号处于未决状态
// 未决状态对的信号需要备处理
// 但是在处理之前需要和另一个叫做阻塞信号集的对应比特位进行比较
// 如果对应位置是1,那么就说明信号被阻塞,那么这个信号就不会被处理,直到指变成0
// 阻塞信号集默认不阻塞任何信号,我们可以手动进行设置(调用系统API)

// sigemptyset函数
//     清空信号集中的数据,所有标志位被设置为0
//     参数:set,要设置的信号集
// sigfillset函数
//     设为1
// sigaddset函数
//     设置信号集中的某一个标志位设置为1
// sigdelset 函数
//     和上面的相反,0
// sigismember函数
//     判断某个信号是否阻塞
// 上面的函数都是阻塞信号集的操作函数
// 创建一个信号集
// sigset_t set ;
// // 先清空
// sigemptyset(&set);
// // 判断信号是否在信号集中
// int ret = sigismember(&set,SIGINT);
// if (ret == 0) {
// printf("SIGINT 不阻塞\n");
// }else if(ret == 1) {
// printf("SIGINT 阻塞\n");

// }
// // 添加信号到信号集中
// sigaddset(&set,SIGINT);
// sigaddset(&set,SIGQUIT);
//  ret = sigismember(&set,SIGINT);
// if (ret == 0) {
// printf("SIGINT 不阻塞\n");
// }else if(ret == 1) {
// printf("SIGINT 阻塞\n");

// }
//  ret = sigismember(&set,SIGQUIT);
// if (ret == 0) {
// printf("SIGQUIT 不阻塞\n");
// }else if(ret == 1) {
// printf("SIGQUIT 阻塞\n");

// }
// sigdelset(&set, SIGQUIT);
//  ret = sigismember(&set,SIGQUIT);
// if (ret == 0) {
// printf("SIGQUIT 不阻塞\n");
// }else if(ret == 1) {
// printf("SIGQUIT 阻塞\n");

// }
// 系统调用设置信号集
// sigprocmask
// 该函数可以将我们自定义的信号集映射到内核中
// how:
//     如何对内核中的阻塞信号集进行处理
//         sig_block,mask|set
//         SIG_UNBLOCK: mask^set(异或操作
//         sig_setmask 覆盖内核的指
// sigpending
//     获取内核当中的未决信号集

// 编写一个程序,将所有的常规信号(1-31)的未决状态打印出来
// 设置某些信号是阻塞的,通过键盘来产生这些信号ctrl+?
// 设置2、3信号阻塞
sigset_t set;
sigemptyset(&set);
// 将2、3信号添加到信号集中
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
//修改内核中的阻塞信号集
sigprocmask(SIG_BLOCK,&set, NULL);
int num=0;
while(1) {
    printf("num:%d\n",num);
    if(num == 10){
        // 解除sigint的阻塞
        sigprocmask(SIG_UNBLOCK,&set,NULL);
    }
    num++;
    // 获取当前的未决信号集
    sigset_t pendingset;
    sigemptyset(&pendingset);
    sigpending(&pendingset);
    //遍历bit位
    for(int i=1;i<=32;i++) {
if(sigismember(&pendingset,i)==1){
    printf("1");
}else if(sigismember(&pendingset, i)==0) {
    printf("0");
}else{
    perror("sigismember\n");exit(0);
}


    }printf("\n");sleep(1);
}

//     // 必须在设置定时器之前注册回调函数
// sig_t retr =  signal(SIGALRM,sig_handler);
// if(retr==SIG_ERR) {
//     perror("signal注册");
//     exit(-1);
// }
// struct itimerval new_value;
// // 设置值
// new_value.it_interval.tv_sec = 2;
// new_value.it_interval.tv_usec =0;
// new_value.it_value.tv_sec=3;
// new_value.it_value.tv_usec=0;
// int ret = setitimer(ITIMER_REAL,&new_value,NULL);
// printf("定时器开始\n");
// if (ret==-1){
//     perror("settimer");
//     exit(0);
// }
// getchar();
// pid_t pid = fork();
// if(pid==0){
//     for(int i=0;i<5;i++) {
//         printf("孩子进程%d\n", i);
//         sleep(1);
//     }
// }else if(pid>0) {
//   printf("爹进程\n");
//   sleep(2);
//   printf("傻儿子\n");
//   kill(pid,SIGINT);
// }
return 0;}
/*

    // char * buf;
    // strcpy(buf, "cao nima");return 0;}/*
    // 修改mmap的flags参数,之前使用的是MAP_SHARED
    // 现在我们要用的是MAP_ANON
    int len = 1204;
    void *ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
    if (ptr == MAP_FAILED)
    {
        perror("mmap");
        exit(0);
    }
    // 父子进程间通信
    int pid = fork();
    if (pid > 0)
    {
        strcpy((char *)ptr, "hello world");
        wait(NULL);
    }
    else if (0 == pid)
    {
        sleep(1);
        printf("%s\n", (char *)ptr);
    }
    // 释放内存映射区
    int ret = munmap(ptr, len);
    // int fd = open("englsih.txt", O_RDONLY);
    // // 获取原始文件的大小
    // int len = lseek(fd, 0, SEEK_END);
    // // 创建一个新文件,并对其大小进行拓展
    // int fd1 = open("cpy.txt", O_CREAT | O_RDWR, 0664);
    // truncate("cpy.txt", len);
    // write(fd1, " ", 1);
    // // 分别进行内存映射
    // void *ptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
    // void *ptr1 = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
    // if (ptr == MAP_FAILED)
    // {
    //     perror("mmap");
    //     exit(0);
    // }
    // if (ptr1 == MAP_FAILED)
    // {
    //     perror("mmap");
    //     exit(0);
    // }
    // // 内存拷贝
    // memcpy(ptr1, ptr, len);
    // munmap(ptr1, len);
    // munmap(ptr, len);
    // close(fd1);
    // close(fd);
    return 0;
}
*/

可以看到在解除sigint信号的阻塞之前,无论怎么按Ctrl+C都是无法结束程序的,如果在第10秒之前你输入了ctrl+c,那么在第10秒的时候程序就会结束

或者你在10秒之后输入了ctrl+c,那么程序会立马结束