《Linux C编程实战》笔记:信号的发送

信号的发送主要由函数kill、raise、sigqueue、alarm、setitimer以及abort来完成

kill函数

kill函数用来发送信号给指定的进程。

#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig);

该函数的行为与第一个参数pid有关,第二个参数sig表示信号编号。

  • 如果pid是正数,则发送信号sig给进程号为pid的进程
  • 如果pid为0,则发送信号sig给当前进程所属的进程组里的所有进程
  • 如果pid为-1,则把信号sig广播至系统除1号进程(init进程)和自身以外的所有进程
  • 如果pid是比-1还小的负数,则发送信号sig给属于进程组-pid(也就是pid的绝对值) 的所有进程
  • 如果参数sig是0,则kill仍执行正常的错误检查,但不发送信号。可以利用这一点来确定某新城是否有权向另外一个进程发送信号。如果向一个并不存在的进程发送空信号,则kill返回-1,errno被设置为ESRCH

函数执行成功返回0,当有错误发生时返回-1,错误代码存入errno。

注意:只有具有root权限的进程才能向其他任意进程发送信号,非root权限的进程只能向属于同一个组或同一个用户的进程发送信号。

示例程序1

该示例程序实现了自己的kill命令。在shell中kill命令也是用来发送信号的,我们用代码仿照shell的kill命令,但是不支持-l选项(显示信号编号)

//本程序只支持按信号的编号发送信号
#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char **argv){
    int i,j;
    int signum=SIGTERM;//默认发送SIGTERM
    pid_t pid;
    //首先检查参数,要么是只有一个参数,也就是pid,要么是三个参数,也就是 -s signum pid
    if(argc!=2&&argc!=4){
        printf("Usage:./my_kill <-s signum>[PID]\n");
        exit(0);
    }
    for(i=1;i<argc;i++){
        //如果有-s,找到-s后面的参数,它就是signum
        if(!strcmp(argv[i],"-s")){
            signum=atoi(argv[i+1]);
            break;
        }
    }
    if(argc==2){
        //如果只有一个参数,它就是pid
        pid=atoi(argv[1]);
    }else{
        for(j=1;j<argc;j++){
            //i是在-s,所以j=i+2的时候就指向的是pid
            if(j!=i&&j!=i+1){
                pid=atoi(argv[j]);
                break;
            }
        }
    }
    if(kill(pid,signum)<0){
        perror("kill");
        exit(1);
    }
    return 0;
}

运行的方式:./my_kill -s 2(这是signum) 2568(这是pid)

这个例子可以配合之前几节写的信号接收的程序使用来测试

raise函数

raise函数是ANSI C而非POSIX标准定义的,用来给调用它的进程发送信号。

#include<signal.h>
int raise(int sig);

示例程序2

这里用raise函数写一个自发自收的信号

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
void process(int signum){
    printf("recv!\n");
}
int main(int argc,char **argv){
    signal(SIGINT,process);
    raise(SIGINT);
    return 0;
}

这都很简单,就不解释了。

sigqueue函数

这个函数支持信号带有参数,从而可以与函数sigaction配合使用

#include<signal.h>
int sigqueue(pid_t pid,int sig,const union sigval value);

sigqueue的另一个与kill的不同点是它不能给一组进程发送信号

参数value是一个union共用体,定义如下

union sigval{
    int sival_int;
    void *sival_ptr;
};

union的特点就是只能是其中一个。也就是说信号携带的要么是一个整型值,要么是一个void型指针。当接收进程的信号处理函数是由sigaction设置的并且设置了SA_SIGINFO标准,接收进程可以从siginfo_t结构的si_value域取得信号发送时携带的参数

成功执行返回0,发生错误返回-1,错误码存到errno里。

程序3

这个函数书上竟然没有给示例,我尝试自己写一个demo来测试一下。

首先是接收方的程序,设置一下sigaction

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
void receive_process(int signum,siginfo_t *info_ptr,void *unused_ptr){
    printf("recv!\n");
    printf("data is:%d\n",info_ptr->si_value.sival_int);
}
int main(int argc,char **argv){
    printf("my pid:%d\n",getpid());
    struct sigaction act;
    act.sa_flags=SA_SIGINFO;
    act.sa_sigaction=receive_process;
    sigaction(SIGINT,&act,nullptr);
    while(1);
    return 0;
}

然后是发送方的程序

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc,char **argv){
    pid_t pid=atoi(argv[1]);
    int data=atoi(argv[2]);
    union sigval value;
    value.sival_int=data;
    sigqueue(pid,SIGINT,value);
    return 0;
}

运行结果如图

完美的发送和接收,证明讲的确实没问题。

我在上一节里写的si_value的类型是sigval_t,我去源码里翻了下, sigval_t和union sigval是一样的,只是重新命名了。 

sigaction不会写的可以看我之前写的文章《Linux C编程实战》笔记:信号的捕捉和处理-CSDN博客

alarm函数

alarm函数可以用来设置定时器,定时器超时将产生SIGALRM信号给调用进程。

#include<unistd.h>
unsigned int alarm(unsigned int seconds);

经过seconds秒后,内核将给调用该函数的进程发送SIGALRM信号,如果seconds为0,则不再发送SIGALRM信号。最新一次调用alarm函数将取消之前一次的设定。

注意:alarm只设定为发送一次信号,如果要多次发送,就要对alarm进行多次调用。

示例程序4

该示例程序模拟网络命令ping的功能。

其实我也不知道ping是干啥的...反正跟着敲吧。

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
void send_ip(){
    printf("send a icmp echo request packet\n");
}
void recv_ip(){
    while(1);
}
void handler_sigalarm(int signo){
    send_ip();
    alarm(2);
}
int main(int argc,char **argv){
    signal(SIGALRM,handler_sigalarm);
    raise(SIGALRM);//触发一个SIGALRM信号给本进程
    recv_ip();
    return 0;
}

其实就是一直在发这段话罢了。整个程序也很好懂,就不多讲了。

getitimer/setitimer函数

与alarm函数一样,setitimer函数也是用来设置定时器的,且alarm和setitimer使用的是同一个定时器,因此会相互影响。setitimer要比alarm具有更多的功能。

#include<sys/time.h>
int getitimer(int which,struct itimerval *value);
int setitimer(int which,const struct itimerval *value,struct itimerval *ovalue);

第一个参数which用来指定使用哪一个定时器,根据参数which可单独设定每个定时器,定时器的种类如下:

 参数value用来指定定时器的时间,结构struct itimerval的定义如下:

struct itimerval{
    struct timeval it_interval;
    struct timeval it_value;
}
//解释一下setitimer里这个结构体的使用,首先定时器时间是it_value,这个计完后会发一个信号,之后
//it_value会重新变为it_interval,并且之后一直以it_interval为间隔循环计时,计到0也会发送信号
struct timeval{
    long tv_sec;//秒数
    long tv_usec;//微秒
}

对于函数getitimer,如果存在由which指定的定时器,则将剩余时间保存在it_value中,该定时器的初始值保存在it_interval中;如果不存在指定类型的定时器,则将value置为0返回。执行成功返回0,当有错误发生时则返回-1,错误代码存入errno中。

示例程序5

#include<stdio.h>
#include<sys/time.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
//信号处理程序
void handler_sigtimer(int signo){
    switch (signo)
    {
    case SIGALRM:
        printf("recv SIGALRM\n");
        break;
    case SIGPROF:
        printf("recv SIGPROF\n");
        break;
    default:
        break;
    }
}
int main(int argc,char **argv){
    struct itimerval value;
    //安装信号处理函数
    signal(SIGALRM,handler_sigtimer);
    signal(SIGPROF,handler_sigtimer);
    //初始化value结构
    value.it_value.tv_sec=1;    //第一次1秒触发信号
    value.it_value.tv_usec=0;
    value.it_interval.tv_sec=5;    //第二次之后都是5秒触发信号
    value.it_interval.tv_usec=0;
    //设置定时器
    setitimer(ITIMER_REAL,&value,nullptr);
    setitimer(ITIMER_PROF,&value,nullptr);
    while(1);
    return 0;
}

程序设置了两个定时器ITIMER_REAL和ITIMER_PROF。系统经过1秒后,将触发一个SIGALRM信号,以后每5秒触发一个SIGALRM信号。按照程序执行时消耗的时间以及内核因本程序消耗的时间来计时。第一次经过一秒后将触发一个SIGPROF信号,以后每5秒触发一个SIGPROF信号。

abort函数

#include<stdlib.h>
void abort(void);

如果进程设置了信号处理函数以捕获SIGABRT信号,且信号处理函数不返回(如使用longjmp),则abort()不能终止进程。abort()终止进程时,所有打开的流(如i/o流、文件流)均会被刷新和关闭。如果进程设置了SIGABRT被阻塞或忽略,abort()将覆盖这种设置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/343920.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源模型应用落地-业务整合篇(四)

一、前言 通过学习第三篇文章&#xff0c;我们已经成功地建立了IM与AI服务之间的数据链路。然而&#xff0c;我们目前面临一个紧迫需要解决的安全性问题&#xff0c;即非法用户可能会通过获取WebSocket的连接信息&#xff0c;顺利地连接到我们的服务。这不仅占用了大量的无效连…

jenkins安装配置,使用Docker发布maven项目全过程记录(2)

2、使用Docker发布Maven项目过程的配置 首先说明&#xff0c;在这里仅介绍我使用Jenkins的发布过程的配置&#xff0c;不涉及Dockerfile、docker-compose.yml文件的内容。 2.1 创建Item 在这里&#xff0c;输入item名称&#xff0c;我使用的Freestyle project&#xff0c;点击…

MSP430仿真器使用常见问题

一、 主要是驱动安装问题 有用户反应驱动安装不上&#xff0c;按照用户手册操作一直不能安装成功。 可以尝试如下步骤进行安装。 1. 双击设备管理器中无法安装或者提示有错误的430仿真器设备 选择驱动程序——更新驱动程序 选择手动安装 选择从电脑设备驱动列表中安装 弹出下…

Spring Security 6 学习-1

什么是 Spring Security Spring Security文档 Spring Security中文文档 Spring Security 是 Spring 家族中的安全型开发框架&#xff0c;主要解决三大方面问题&#xff1a;认证&#xff08;你是谁&#xff09;、授权&#xff08;你能干什么&#xff09;、常见攻击保护&#xff…

mysql INSERT数据覆盖现有元素(若存在)

INSERT...ON DUPLICATE KEY UPDATE的使用 如果指定了ON DUPLICATE KEY UPDATE&#xff0c;并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值&#xff0c;则会更新ON DUPLICATE KEY UPDATE关键字后面的字段值。 例如&#xff0c;如果列a被定义为UNIQUE&#xff0…

机器学习实验3——支持向量机分类鸢尾花

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;数据预处理&#x1f9e1;&#x1f9e1;代码认识数据相关性分析径向可视化各个特征之间的关系图 &#x1f9e1;&#x1f9e1;支持向量机SVM求解&#x1f9e1;&#x1f9e1;直觉…

JavaEE-Nuxt中的vuex

Nuxt中的vuex 参考&#xff1a;https://v2.nuxt.com/docs/directory-structure/store 3.1 根模块数据操作 步骤一&#xff1a;创建 store/index.js 添加一个 counter变量&#xff0c;并可以继续累加操作 export const state () > ({counter: 0 })export const mutations …

用户反映在浏览器中使用AI工具 Copilot 遇到严重卡顿问题,微软官方给出初步解释

近日&#xff0c;多位用户反馈在使用Edge和Chrome浏览器中的Copilot时出现卡顿问题&#xff0c;甚至需要重启浏览器才能解决。对此&#xff0c;微软广告和网络服务部门CEO米哈伊尔帕拉欣表示&#xff0c;问题可能与Edge浏览器的“效率模式”有关。 微软中国官方网址链接&#x…

【GitHub项目推荐--12 年历史的 PDF 工具开源了】【转载】

最近在整理 PDF 的时候&#xff0c;有一些需求普通的 PDF 编辑器没办法满足&#xff0c;比如 PDF 批量合并、编辑等。 于是&#xff0c;我就去 GitHub 上看一看有没有现成的轮子&#xff0c;发现了这个 PDF 神器「PDF 补丁丁」&#xff0c;让人惊讶的是这个 PDF 神器有 12 年的…

C#,计算几何,鼠标点击绘制 (二维,三次)B样条曲线的代码

B样条&#xff08;B-Spline&#xff09;是常用的曲线拟合与插值算法之一。 这里给出在 Form 的 图像 Picturebox 组件上&#xff0c;按鼠标点击点绘制 &#xff08;三次&#xff09;B样条曲线的代码。 2022-12-05 修改了代码。 1 文本格式 using System; using System.Data; …

机器人制作开源方案 | 智能特殊环境清洗机器人

作者&#xff1a;达德聪 袁豪杰 杨垚 单位&#xff1a;邢台学院 指导老师&#xff1a;王承林 杨立芹 智能特殊环境清洗机器人基于STC系列单片机为核心&#xff0c;驱动摄像头模块、超声波模块、ESP8266无线模块、自动寻迹模块、舵机模块、语音识别模块&#xff0c;实现自主寻…

《WebKit 技术内幕》学习之十二(2):安全机制

2 沙箱模型 2.1 原理 一般而言&#xff0c;对于网络上的网页中的JavaScript代码和插件是不受信的&#xff08;除非是经过认证的网站&#xff09;&#xff0c;特别是一些故意设计侵入浏览器运行的主机代码更是非常危险&#xff0c;通过一些手段或者浏览器中的漏洞&#xff0c…

中仕教育:事业编招考全流程介绍

一、报名阶段 1. 了解查看招聘信息&#xff1a;查看各类事业编岗位的招聘信息&#xff0c;包括岗位职责、招聘条件、报名时间等。 2. 填写报名表&#xff1a;按照要求填写报名表&#xff0c;包括个人信息、教育背景、工作经历等内容。 3. 提交报名材料&#xff1a;将报名表及…

作物品种测试——批量获取试验站点直线距离

参考资料&#xff1a; 根据经纬度计算两地之间的距离_经纬度计算距离-CSDN博客 用于计算不同试验站点之间的距离&#xff0c;可以据此来评估各试验站点分布的合理性。 1、首选需要准备excel文件&#xff0c;用于存放各试验站点的经纬度信息。数据列内容如下&#xff1a; 2、…

[Android] Android文件系统中存储的内容有哪些?

文章目录 前言root 文件系统/system 分区稳定性:安全性: /system/bin用来提供服务的二进制可执行文件:调试工具:UNIX 命令&#xff1a;调用 Dalvik 的脚本(upall script):/system/bin中封装的app_process脚本 厂商定制的二进制可执行文件: /system/xbin/system/lib[64]/system/…

x-cmd pkg | perl - 具有强大的文本处理能力的通用脚本语言

目录 介绍首次用户技术特点竞品进一步阅读 介绍 Perl 是一种动态弱类型编程语言。Perl 内部集成了正则表达式的功能&#xff0c;以及巨大的第三方代码库 CPAN;在处理文本领域,是最有竞争力的一门编程语言之一 生态系统&#xff1a;综合 Perl 档案网络 (CPAN) 提供了超过 25,0…

记一次Flink通过Kafka写入MySQL的过程

一、前言 总体思路&#xff1a;source -->transform -->sink ,即从source获取相应的数据来源&#xff0c;然后进行数据转换&#xff0c;将数据从比较乱的格式&#xff0c;转换成我们需要的格式&#xff0c;转换处理后&#xff0c;然后进行sink功能&#xff0c;也就是将数…

记一次压测程序时的OOM分析过程

背景&#xff1a;在一个项目调优的过程中&#xff0c;丰富了一些组件后&#xff0c;再次对项目进行压测&#xff0c;发现和之前的性能差距甚大&#xff0c;并且每次运行一段时间后&#xff0c;延迟骤增&#xff0c;带宽骤降&#xff0c;查看程序日志&#xff0c;发现了 OutOfMe…

平复一下心情 愉快一下 部署一款在线图书馆

注意:国内不让随便搞线上图书馆 注意:国内不让随便搞线上图书馆 注意:国内不让随便搞线上图书馆 1安装 1.1.拉取镜像 docker pull talebook/talebook 1.2.创建目录 mkdir -p /opt/talebook 1.3.创建并启动容器 docker run -d --name talebook -p 10015:80 -v /opt/taleb…

机器学习实验2——线性回归求解加州房价问题

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;数据预处理&#x1f9e1;&#x1f9e1;代码缺失值处理特征探索相关性分析文本数据标签编码数值型数据标准化划分数据集 &#x1f9e1;&#x1f9e1;线性回归&#x1f9e1;&am…
最新文章