首页 > 系统相关 >系统编程(进程通信--信号进阶)

系统编程(进程通信--信号进阶)

时间:2025-01-18 10:03:11浏览次数:3  
标签:printf 定时器 进阶 -- 编程 int handler 信号 signum

常见问题

解决 vscode 远程连接虚拟机上 ubuntu 系统,在编写代码时用到的 Linux 系统函数或者某些
常量不提醒或者报红色波浪线的问题:
在这里插入图片描述

信号的屏蔽和解除

在这里插入图片描述
在这里插入图片描述

信号的屏蔽和解除屏蔽函数的基本使用:

#include <stdio.h>
#include "header.h"

void handler(int signum)
{
    printf("%d--%d\n", getpid(), signum);
}

// 信号的发送和信号的处理是异步的(各自执行各自的)
// 当信号到达后,就会执行信号处理函数,此时sleep打断,当执行函数执行完毕后,sleep不会继续执行
int main(int argc, char const *argv[])
{
    printf("当前进程id是 %d\n", getpid());

    // 循环给所有信号绑定处理函数
    for (int i = 1; i <= 64; i++)
    {
        if (i == SIGKILL || i == SIGSTOP || i == 32 || i == 33) // 9, 19, 32, 33
        {
            continue;
        }
        // 给其他信号绑定处理函数
        signal(i, handler);
    }

    // 定义信号集的结构体变量
    sigset_t set;
    // 清理集合中的信号
    sigemptyset(&set);

    // 填充所有信号
    //  sigfillset(&set);
    for (int i = 1; i <= 64; i++)
    {
        if (i == 32 || i == 33)
        {
            sigaddset(&set, i);
        }
    }

    // 删除某个信号
    sigdelset(&set, 12);

    // 调用函数屏蔽所有信号
    int r = sigprocmask(SIG_BLOCK, &set, NULL);
    if (r == -1)
    {
        perror("sigprocmask failed");
        return -1;
    }
    puts("所有信号已经屏蔽!");

    // 过一段时间,//延时20秒
    sleep(20);

    // 解除所有被屏蔽的信号
    int r2 = sigprocmask(SIG_UNBLOCK, &set, NULL);

    if (r2 == -1)
    {
        perror("unmask sigprocmask failed");
        return -1;
    }
    // 延时20秒
    sleep(20);
    puts("所有信号已经解除屏蔽!");

    puts("程序即将退出!");
    return 0;
}

在这里插入图片描述

可靠信号和不可靠信号

#include <stdio.h>
#include "header.h"

void handler(int signum)
{
    printf("%d--%d\n", getpid(), signum);
}

//信号的发送和信号的处理是异步的(各自执行各自的)
//当信号到达后,就会执行信号处理函数,此时sleep打断,当执行函数执行完毕后,sleep不会继续执行
int main(int argc, char const *argv[])
{
    printf("pid=%d\n", getpid());

    //循环给所有信号绑定处理函数,除去9
    for(int i = 1; i<=64; i++)
    {
        if(i == SIGKILL || i == 32 || i==33)
        {
            continue;
        }
        //绑定处理函数
        signal(i, handler);
    }

    sigset_t set;
    //清空操作
    sigemptyset(&set);
    //填充所有信号
    sigfillset(&set);
    //调用函数屏蔽信号
    if (-1 == sigprocmask(SIG_BLOCK, &set, NULL))
    {
        perror("sig mask failed");
        return -1;
    }
    puts("所有信号已经被屏蔽\n");

    //循环给当前进程发送多次可靠信号---
    for(int i = 0; i<5; i++)
    {
        //当屏蔽解除后,所有可靠信号都接受到并执行了处理函数
        //raise(46);
        //当屏蔽解除后,所有不可靠信号只接收到一个,因为其他信号嵌套丢失了
        raise(6);
    }

    puts("10秒之后解除屏蔽");
    sleep(10);

    //调用函数解除屏蔽
    if (-1 == sigprocmask(SIG_UNBLOCK, &set, NULL))
    {
        perror("sig unmask failed");
        return -1;
    }
    
    puts("进程结束");
    return 0;
}

在这里插入图片描述

发送信号并携带数据

在这里插入图片描述
在这里插入图片描述

发送带数据的信号代码:

#include <stdio.h>
#include "header.h"

int main(int argc, char const *argv[])
{
    //通过命令行传输数据
    if (argc < 2)
    {
        puts("缺少参数!");
        return -1;
    }

    printf("argv[1]: %s\n", argv[1]);

    //定义变量存储信号编号
    int signum;
     int a =0;
    while (1)
    {
        printf("请输入要发送的信号:\n");
        scanf("%d", &signum);
        //排除非信号编号的值
        if (signum<1 || signum >64 || signum == 32 || signum == 33)
        {
            printf("不能发送这样的信号!\n");
            break;
        }
        //定义共用体作为写到的数据块
        union sigval value;
        //设置携带的数据
        //value.sival_int = 666666;
        a = 200;
        value.sival_ptr = &a;
        printf("send: %p\n", &a);
        //调用sigqueue函数发送信号
        int r = sigqueue(atoi(argv[1]), signum, value);
        if (r == -1)
        {
            perror("sigqueue failed");
            return -1;
        }
    }
    return 0;
}

在这里插入图片描述

接收带数据的信号代码

#include <stdio.h>
#include "header.h"


//类型重命名
typedef struct sigaction SigAction_t;

//定义信号处理函数
// void handler(int signum)
// {
//     printf("rcv: %d\n", signum);
// }

void data_handler(int signum, siginfo_t* info, void* a)
{
    if (signum == SIGINT)
    {
        printf("si_value: %p\n", info->si_value.sival_ptr);
        printf("rcv: %d, %d, %d, %d\n", info->si_pid, info->si_int, info->si_signo, *(int*)(info->si_value.sival_ptr));
    }    
}

int main(int argc, char const *argv[])
{
    //定义sigaction函数需要的结构体变量
    SigAction_t act1;
    //act1.sa_handler = handler;

    //指定能够接收数据的处理函数
    act1.sa_sigaction = data_handler;

    act1.sa_flags = SA_SIGINFO;
    //清空默认的信号集
    sigemptyset(&act1.sa_mask);

    //调用函数接收发送过来的消息, ctrl+c
    int r = sigaction(SIGINT, &act1, NULL);
    if (r == -1)
    {
        perror("sigaction failed");
        return -1;
    }

    //死循环--保活程序等待信号的到来,不断的打印当前进程id
    while (1)
    {
        printf("main running ..... %d\n", getpid());
        sleep(1);
    }
    return 0;
}

问题的原因: 虽然可以携带指针类型的数据,但发送程序和接收程序是两个进程,两个进程
是独立的虚拟内存空间,所以不能用一个进程的内存地址获取另外一个进程同样内存地址上的
数据;故运行会报段错误(野指针访问数据)

在这里插入图片描述

解决办法:在父子进程间可以发送携带指针的数据,因为子进程拷贝了父进程的虚拟内存空间
和数据,所以可以通过同样的内存地址找到同样的数据

定时器 alarm

alarm 是一次性定时器,如果要实现循环定时器,需要在处理函数中再次调用 alarm 函数
alarm 的使用:
在这里插入图片描述

#include <stdio.h>
#include "header.h"


void handler(int signum)
{
    printf("rcv: %d\n", signum);
    alarm(5);
}

int main(int argc, char const *argv[])
{
    //调用alarm函数设置定时器
    alarm(3);

    //给定时器绑定处理函数
    signal(SIGALRM, handler);
    //让程序每隔1秒打印一点内容,观察到定时器在运行
    while (1)
    {
        printf("main  running.... %d\n", getpid());
        sleep(1);
    }
    
    return 0;
}

在这里插入图片描述

微秒定时器:ualarm 函数 微妙定时器是一个循环定时器,微妙定时器只能设置小于 1 秒的时
间,如果>= 1 秒,默认是1 秒(0.999999… 秒)
在这里插入图片描述

//调用ualarm函数设置定时器
/*
arg1: 等候多少微妙发送第一次定时器信号
arg2: 之后每隔多少微妙发送定时器信号
所以ualarm也叫循环定时器
注意:该定时器的参数必须小于1秒, 否则不起作用,默认当作一秒处理
*/
//ualarm(500000, 30000);  // 0.5,  0.03秒

//注意:该定时器的参数必须小于1秒, 否则不起作用,默认当作一秒处理
//ualarm(3000000, 5000000);

//给定时器绑定处理函数
#include <stdio.h>
#include "header.h"


//ualarm: 微妙定时器
void handler(int signum)
{
    printf("rcv: %d\n", signum);
    
}

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

    signal(SIGALRM, handler);
    //让程序每隔1秒打印一点内容,观察到定时器在运行
    while (1)
    {
        printf("main  running.... %d\n", getpid());
        sleep(1);
    }
    
    return 0;
}

在这里插入图片描述

pause 函数

该函数可以暂定当前进程 基本使用代码:

#include <stdio.h>
#include "header.h"


void handler(int signum)
{
    printf("rcv: %d\n", signum);
    alarm(5);
}

int main(int argc, char const *argv[])
{
    //调用alarm函数设置定时器
    alarm(3);

    //给定时器绑定处理函数
    signal(SIGALRM, handler);
    //让程序每隔1秒打印一点内容,观察到定时器在运行

    //调用pause函数暂定
    pause();

    while (1)
    {
        printf("main  running.... %d\n", getpid());
        sleep(1);
    }
    
    return 0;
}

在这里插入图片描述

标签:printf,定时器,进阶,--,编程,int,handler,信号,signum
From: https://blog.csdn.net/weixin_69851948/article/details/145213489

相关文章

  • 【渗透 Tips】解决Edge的IE模式下无法抓包情况
    问题说明        在日常渗透中往往避免不了站点的环境适配问题,有一些站点只能使用IE模式访问,此时便会想着可能使用内置proxy插件代理至抓包软件即可,事实上这并不能很好解决。        如上图所示,即使挂上了yakit代理也无济于事;同时,尝试打开开发者模式进行抓包会......
  • 深度学习中的迁移学习:使用预训练模型进行图像分类
    深度学习中的迁移学习:使用预训练模型进行图像分类介绍迁移学习是一种机器学习方法,其中一个模型在某个任务上进行预训练,并将该知识转移到新的但相关的任务中。深度学习中的迁移学习常用于图像分类,通过利用预训练模型(例如VGG、ResNet、Inception等)显著减少新任务所需的训......
  • AkShare-股票数据-资金流向
    社区首页>专栏>AkShare-股票数据-资金流向AkShare-股票数据-资金流向发布于 2020-05-2000:49:032.1K04代码可运行举报文章被收录于专栏:数据科学实战作者寄语继续扩充昨天更新的资金流数据数据:个股资金流、个股资金流排名、大盘资金流、板块......
  • 2023年05月机器人一级理论参考答案
    一、单选题1、机器人的电源相当于人类的?()A、大脑B、皮肤C、血管D、心脏2、如图哪个工具是羊角锤?()A、aB、bC、cD、d3、如图下列最省力的滑轮组是?()A、aB、bC、cD、d4、如图要想从地面爬到M点,哪条路最省力?()A、aB、bC、cD、d5、下列哪个齿轮组是齿......
  • 陪玩系统源码,继承和混入的区别
    混入@mixinblock{.a{width:96%;margin-left:2%;border-radius:10px;border:1pxsolid#333;}}.container{@includeblock;} 转化为:.container.a{width:96%;margin-left:2%;border-r......
  • 【2024年华为OD机试】 (A卷,200分)- 硬件产品销售方案(Java & JS & Python&C/C++)
    一、问题描述题目描述某公司目前推出了AI开发者套件,AI加速卡,AI加速模块,AI服务器,智能边缘多种硬件产品,每种产品包含若干个型号。现某合作厂商要采购金额为amount元的硬件产品搭建自己的AI基座。例如当前库存有N种产品,每种产品的库存量充足,给定每种产品的价格,记为price(不......
  • Prometheus +VictoriaMetrics+Granafa安装部署
    测试环境prometheus-2.54.1.linux-amd64.tar.gz下载地址:https://www.prometheus.io/download/https://github.com/prometheus/prometheus/releases/download/v2.54.1/prometheus-2.54.1.linux-amd64.tar.gznode_exporter-1.8.2.linux-amd64.tar.gz下载地址:https://github.c......
  • 【2024年华为OD机试】 (B卷,100分)- 流水线(Java & JS & Python&C/C++)
    一、问题描述题目描述一个工厂有m条流水线,来并行完成n个独立的作业,该工厂设置了一个调度系统,在安排作业时,总是优先执行处理时间最短的作业。现给定流水线个数m,需要完成的作业数n,每个作业的处理时间分别为t1,t2,...,tn。请你编程计算处理完所有作业的耗时为多......
  • 股票API接口使用python、JAVA等多种语言实例代码演示免费获取实时数据、历史数据、CDM
    ​最新整理的股票API接口,下方所有接口链接均可直接点击验证,查看返回的数据。沪深两市股票列表股票API接口链接(可点击验证):https://api.mairui.club/hslt/list/LICENCE-66D8-9F96-0C7F0FBCD073【实时数据接口】沪深两市实时交易数据接口股票API接口链接(可点击验证):https:......
  • Ubuntu 设置虚拟内存
    虚拟内存(交换空间)可以帮助在物理内存不足时,系统仍然能够正常运行。1.检查现有交换空间首先,检查系统是否已经配置了交换空间:sudoswapon--show如果没有任何输出,说明当前没有启用交换空间。2.创建交换文件你可以通过创建一个交换文件来增加虚拟内存。以下是创建6GB交换......