系统编程-信号

news2025/1/12 1:08:05

6 信号与管道 1

目录

6 信号与管道 1

信号

信号的概念

信号的使用

信号的发送

通过函数来实现信号的发送

信号改造函数(重点)

给自己发送信号函数

定时闹钟函数

暂停进程的函数

例题:

代码一:

代码二:

代码分析


-- linux系统下的进程间通信

  • 一共六种
  • 信号 管道 消息队列 共享内存 信号量集 套节字

信号

信号的概念

-- 信号是进程在运行过程中,由自身产生或由进程外部发过来的消息(事件)。
-- 信号是硬件中断的软件模拟(软中断) 。

-- 每一个信号用一个整型常量宏表示,以 SIG 开头,比如 SIGCHLD、SIGINT 等, 它们在系统头文件<signal.h> 中定义, 也可以通过在终端键入kill -l查看信号列表,或者键入 man 7

alt text

-- 1~31号信号是从unix上面继承过来的 不可靠信号 没有排队机制
-- 34~64是后面补充的信号 可靠信号
-- 信号大部分都是让进程死亡的

信号的使用

-- 主要去搞清楚 一些信号是如何产生的以及如何使用

  • SIGHUP:从终端上发出的结束信号; 1
  • SIGINT:来自键盘的中断信号(Ctrl-C); 2
  • SIGQUIT:来自键盘的退出信号(Ctrl-\); 3
  • SIGFPE: 浮点异常信号(例如浮点运算溢出);
  • SIGKILL:该信号结束接收信号的进程; 9
  • SIGALRM:进程的定时器到期时,发送该信号; 14
  • SIGTERM: kill 命令发出的信号;
  • SIGCHLD:标识子进程停止或结束的信号; 17
    -- 子进程给父进程主动发送的信号(有以下三种情况父进程会向子进程发送信号)
    -- 1、子进程死亡
    -- 2、子进程由运行转为暂停
    -- 3、子进程由暂停转为继续运行
  • SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号 19
  • SIGCONT: 18信号 继续运行信号

信号的发送

-- 在终端上发送信号

  • kill -num pid
  • 发送第num个信号到pid这个进程上去

例如:

alt text

alt text

通过函数来实现信号的发送

-- 函数头文件

  • #include <sys/types.h>
  • #include <signal.h>

-- 函数原型

  • int kill(pid_t pid, int sig);

-- 函数的作用:

  • 给指定的进程发送一个信号

-- 函数的参数:

  • pid:要给哪一个进程发送信号
  • sig:发送的信号

-- 函数的返回值:

  • 成功 0
  • 失败 -1

alt text

信号改造函数(重点)

-- 可以让信号原本的效果消失, 转而去执行相应的函数

-- 函数头文件

  • #include <signal.h>

-- 函数原型

  • sighandler_t = void (*) (int)
  • typedef void (*sighandler_t)(int);
  • sighandler_t signal(int signum, sighandler_t handler);

-- 函数的作用:

  • 将第一个参数中所填写的信号进行改造
  • 让他原本的效果消失
  • 接收到这个信号我们的进程会去运行 第二个参数所填写函数

-- 函数的参数:

  • signum:填写要进行改造的信号
  • 9信号、18 继续、 19 暂停不可以被改造和忽略
  • handler:函数指针指向void (*)(int )类型的函数
  • 当signal函数运行完之后
  • 再次接收到signum信号 会调用handler所指向的函数
  • handler如果参数选SIG_DFL,信号的改变就会恢复默认操作
  • SIG_IGN 对该信号进行忽略

-- 函数的返回值:

  • 成功返回 第二个参数的地址
  • 失败返回 SIG_ERR

alt text

alt text

给自己发送信号函数

--- 函数头文件

  • #include <signal.h>

-- 函数原型

  • int raise(int sig)

-- 函数的作用:

  • 给当前掉用该函数的进程发送一个信号

-- 函数的参数:

  • sig:要给自己发送的信号

-- 函数的返回值:

  • 成功 0
  • 失败 非 0

alt text

定时闹钟函数

-- 函数头文件

  • #include <unistd.h>

-- 函数原型

  • unsigned int alarm(unsigned int seconds);

-- 函数的作用

  • 定一个闹钟 计时结束之后会给当前进程发送一个闹钟信号

-- 函数的参数:

  • seconds:要计时的秒数
  • 给0表示取消之前定的闹钟

-- 函数的返回值:

  • 如果前面定过闹钟返回 上一个闹钟的剩余秒数
  • 如果前面没有定义过闹钟,返回 0

alt text

暂停进程的函数

-- 函数头文件

  • #include <unistd.h>

-- 函数原型

  • int pause(void); -- 函数的作用:
  • 当程序运行到 pause 函数的时候 会暂停
  • 当捕获到一个信号的时候 会解除暂停

-- 函数的返回值

  • 解除暂停返回 -1

alt text

例题:

-- 实现无界面的 MP3 播放器

-- 能实现 上下切歌、播放、暂停、自动播放功能

-- 需要依靠改造 17 信号来实现

-- 17 信号的发出条件 (子进程的状态发生了改变)

  • 1 子进程死亡 会 发出 17 信号给父进程
  • 2 由运行转为暂停的时候也会发送 17 信号
  • 3 由暂停转为继续的时候也会发送 17 信号

alt text

alt text

代码一:

#include "stdio.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include "string.h"
#include "unistd.h"
#include <stdlib.h>
#include "signal.h"


char * name[20] ={0};
int count = 0;
int i = 0;
pid_t pid;
//子进程被暂停和继续也会发送17信号
//子进程死亡的时候发送的17信号
//需要判断子进程是否存活
void func(int a)
{
    printf("接收到17信号\n");
    //wait(NULL);会阻塞
    pid_t p = waitpid(pid,NULL,WNOHANG);
    if(p == 0)//子进程没有死亡
        return ;
    i++;//偏移下标
    if(i == count)//判断是否超了
        i = 0;
    else if(i < 0)
        i = count -1;
    pid = vfork();
    if(pid == 0)
    {
        execlp("mpg123","mpg123",name[i],NULL);
    }
}


int main(int argc,char*argv[])
{
    //1 获取歌曲的绝对路径  目录操作
    DIR * dir = opendir(argv[1]);
    if(dir == NULL)
    {
        perror("opendir()");
        return -1;
    }
    //2 循环读取获取目录下的所有文件
    while(1)
    {
        struct dirent * file = readdir(dir);
        if(file == NULL)
            break;//循环的结束条件
        //查找所有文件后缀为.mp3的文件
        if(strstr(file->d_name,".mp3"))
        {
            //1 把歌的绝对路径存起来
            name[count] = malloc(200);
            sprintf(name[count],"%s/%s",argv[1],file->d_name);
            count++;
        }
    }
    for(int i =0;i<count;i++)
        printf("%s\n",name[i]);
    
    while(1)//失效
    {
        pid = vfork();
        if(pid == 0)
        {
            execlp("mpg123","mpg123",name[i],NULL);
        }
        else if(pid>0)
        {//从键盘输入要进行的操作
            char a = 0;
            signal(17,func);//信号改造函数
            //当接收到17信号 会自动的调用func函数
            //子进程给父进程发送17信号 父进程就会调用func函数

            while(1)
            {
                scanf("%c",&a);//阻塞 等待键盘输入
                getchar();
             //根据不同的值进行不同的操作
                switch(a)
                {   //暂停
                    case 'p': 
                    kill(pid,19);//发送暂停信号
                    printf("暂停\n");
                        break;
                    case 'c':
                    kill(pid,18);//发送继续信号
                    printf("继续\n");
                        break;
                    case 'b':
                    kill(pid,9);
                    i=i-2;
                    printf("上一曲\n");
                        break;
                    case 'n': 
                    //突然发现只要子进程死亡 会自动调用func函数
                    //去播放下一个音乐
                    kill(pid,9);//给指定的进程发送信号
                    printf("下一曲\n");
                        break;
                }
            }
        }
    }
    return 0;   
}

alt text

代码二:



#include "stdio.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include "string.h"
#include "unistd.h"
#include <stdlib.h>

#include <signal.h>

char * name[20] ={0};
int count = 0;
int a=0;
pid_t pid = -1;      // 当前播放的子进程ID

int i=0;
pid_t d =0;

void handleInput() ;
void playSong(int i) ;
void func(int a) ;



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

    if(argc==1)
    {
        printf("请填写参数\n");
        return -1;
    }

    DIR * dir = opendir(argv[1]);
    if(dir == NULL)
    {
        perror("opendir()");
        return -1;
    }


    while(1)
    {
        struct dirent * file = readdir(dir);
        if(file == NULL)
            break;
        if(strstr(file->d_name,".mp3"))
        {
            name[count] = malloc(300);
            sprintf(name[count],"%s/%s",argv[1],file->d_name);
            count++;
        }
    }

    closedir(dir);
    for(int i =0;i<count;i++)
        printf("%s\n",name[i]);


    signal(17,func);

    playSong(i);

    handleInput();

    for (int i = 0; i < count; i++) {  
        free(name[i]);  
    } 

    
    return 0;   
}

void playSong(int i) 
{  
    if (pid != -1) {  
        kill(pid, 9);   
        wait(NULL);  
    }  

    pid = fork();  
    if (pid == 0) {  
        execlp("mpg123", "mpg123", name[i], NULL);   
        exit(1);  
    } 
} 

void func(int a) {  
    if (a == 17) {  
        printf("子进程状态发生改变!\n");  
         
     
        d = waitpid(-1,&a,WNOHANG);
        if(d >0){
            i++;  
        if (i >= count) {  
            i = 0;   
        }  
        playSong(i); 
        }
    }  
} 


void handleInput() {  
    char n;  
    while (1) {  
        printf("请输入命令(p: 暂停, s: 继续, n: 下一首, l: 上一首): \n");  
        scanf(" %c", &n);

        switch (n) {  
            case 'p':  
                if (pid != -1) { 
                    kill(pid, 19); // 暂停子进程  
                }  
                break;  
            case 's':  
                if (pid != -1) {  
                    kill(pid, 18); // 继续子进程  
                }  
                break;  
            case 'n':  
                if (pid != -1) {  
                    kill(pid, 9); // 终止当前进程  
                    wait(NULL);  
                }  
                i++;  
                if (i >= count) {  
                    i = 0; // 循环到第一首歌  
                }  
                playSong(i);  
                break;  
            case 'l':  
                if (pid != -1) {  
                    kill(pid, 9); // 终止当前进程  
                    wait(NULL);  
                }  
                i--;  
                if (i < 0) {  
                    i = count - 1; // 循环到最后一首歌  
                }  
                playSong(i);  
                break;  
            default:  
                printf("无效命令\n");  
                break;  
        }  
    }  
}  


代码分析

alt text

alt text

alt text

alt text

alt text

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS热点分析 (Getis-Ord Gi*)——基于地级市尺度的七普人口普查数据的热点与冷点分析

先了解什么是热点分析 ? 热点分析 (Getis-Ord Gi*) 是一种用于空间数据分析的技术&#xff0c;主要用于识别地理空间数据中值的聚集模式&#xff0c;可以帮助我们理解哪些区域存在高值或低值的聚集&#xff0c;这些聚集通常被称为“热点”或“冷点”&#xff0c;Gi* 统计量为…

Docker介绍、docker安装以及实现docker的远程管理

1.Docker介绍 1.Docker介绍 Docker 是⼀个开源的应用容器引擎&#xff0c;可以实现虚拟化&#xff0c;完全采用“沙盒”机制&#xff0c;容器之间不会存在任何接口。 Docker 通过 Linux Container&#xff08;容器&#xff09;技术将任意类型的应用进行包装&#xff0c;变成一…

PhotoZoom Pro 9:AI加持让图像放大革命性飞跃 PhotoZoom下载

全球领先的数字图片和图形缩放软件——PhotoZoom Pro 9&#xff0c;现已正式发布&#xff01;凭借全新的S-Spline Max AI图像缩放技术&#xff0c;PhotoZoom Pro 9在图像放大质量上达到了前所未有的高度。欢迎各位下载和体验最新的9系列版本。 PhotoZoom Pro 9发布 PhotoZoom9…

远端登录基础配置实验

1.作用 方便远程管理&#xff0c;并且传统的console线只能一个用户访问&#xff0c;而远程管理的协议&#xff0c;可以多用户同时登录。 2.基础远程管理方式 Telnet 协议 telnet协议提供了一种通过终端远程登录到服务器的方式&#xff0c;可以远程对设备进行配置和管…

Prometheus 1:安装(Centos7)

1. 同步时间 因Prometheus对时间精度要求高&#xff0c;所以安装前&#xff0c;需要与NTP同步时间&#xff1a; #设置系统显示时区为 亚洲上海 timedatectl set-timezone Asia/Shanghai#同步当地时间 ntpdate -u cn.pool.ntp.org 2. 同步时间后&#xff0c;从官网下载Prometh…

《Web项目跨域请求后端Api设置Cookie失败问题?》

问题描述&#xff1a; 在web项目中跨域请求api时&#xff0c;api登录成功后需要向域名中设置cookie实现在两个域名下共享&#xff0c;但是登录接口返回成功&#xff0c;响应头中也有set-cookie&#xff0c;实际却无法设置到cookie中… web项目访问时的域名https://b.com/ api所…

解决在IIS下typecho访问网址为localhost的问题

如何在IIS下为typecho开启伪静态 布署好typecho发现访问的地址是这样的 默认的访问地址可以看出是一个php的动态页面&#xff0c;通过配置&#xff0c;可以让地址看起来像是一个静态页面。 开启伪静态需要以下两个步骤&#xff1a; 1、增加IIS Rewrite模块重写规则 2、到typ…

牛客网NC1大数加法

因为要计算的是两个很大很大的数&#xff0c;假设计算出来的数据大于整型的最大值&#xff0c;此时就会出现问题。所以要换个方法来解决问题。 我们应该以字符串的形式来读取两个正整数&#xff0c;并且返回二者相加的结果 我们应该从大数的个位开始&#xff0c;逐级的向上相…

海康VisionMaster使用学习笔记13-串口通信

测试工具 协议介绍 串口在VM中的使用 1. RS232信号线定义 2. RS485信号线定义 3. 创建串口连接 4. 测试VM中串口接收数据

Java Programming Examples

Java Programming Examples Example - Environment How to compile a java file? How to debug a java file? How to set classpath? java -cp java -classpathHow to view current classpath? windows C:> echo %CLASSPATH%linux echo $CLASSPATHHow to set dest…

cbsd 设置网络问题留档

cbsd创建或导入虚拟机&#xff0c;网络不通。使用bridge一直不通&#xff0c;后来是通过设立VALENAT才调通的。 cbsd里网卡设置&#xff0c;里面可以设置网络的上一级 默认是auto 这里选bridge1 试试 失败 选tap1 试试 网络还是不通&#xff0c;但是好消息&#xff0c;是能…

element 使用printJS调用打印功能

1.安装依赖 npm install print-js --save 2.在main.js中全局引用 import printJS from print-js; 3.在页面中使用 <el-button type"success" plain icon"Printer" :disabled"single" click"handlePrint">打印</el-button…

VBA技术资料MF188:将Txt文件转换成Html文件

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

03:电容的充放电特性及应用举例

1.电容的基本特性&#xff1a;电容两端的电压不能突变 2.影响电容两端电压的参数&#xff1a;整个回路中电阻&#xff0c;电容大小 3.如何计算电容的电压变化时间&#xff1f; τRC R1k C1uF 则得到τ1ms的时间 应用&#xff1a;芯片使能延时

测试一组图像生成#Mixlab的异形头

“异形头”或“物体头” 通常指的是一种艺术或设计中的概念&#xff0c;人物的头部被替换为非人体的物体或异形结构。这种设计常见于超现实主义艺术、漫画、动画和游戏中&#xff0c;旨在创造视觉冲击或传达特定的主题和情感。 shadow&#xff1a; 这个概念还蛮有意思的&#x…

作为科协T1级,为何作者纷纷吐血拔草IEEE顶刊TEC,转投TIE和TTE,它输在哪了?

IEEE顶级期刊 本期解析一本能源与发电技术领域SCI&EI&#xff0c;期刊入选中国科协T1级目录&#xff0c;但网友的发表经历却一波三折&#xff0c;大批慕名而来的作者纷纷因其审稿速度很慢而“拔草”&#xff0c;甚至建议转投其它trans类型&#xff0c;这是怎么回事呢 1、期…

2-73 基于matlab的weber能量法求解齿轮时变啮合刚度的程序

基于matlab的weber能量法求解齿轮时变啮合刚度的程序&#xff0c;能够跑出刚度图&#xff0c;通过求解轮齿部分变形、基体变形及局部接触变形这三部分的变形&#xff0c;进而求得综合弹性变形&#xff0c;最终求出时变啮合刚度。程序已调通&#xff0c;可直接运行。 2- 73 齿轮…

乡村养老服务管理系统

TOC springboot549乡村养老服务管理系统pf 绪论 1.1 研究背景 现在大家正处于互联网加的时代&#xff0c;这个时代它就是一个信息内容无比丰富&#xff0c;信息处理与管理变得越加高效的网络化的时代&#xff0c;这个时代让大家的生活不仅变得更加地便利化&#xff0c;也让…

C++竞赛初阶L1-11-第五单元-for循环(25~26课)527: T456436 [NOIP2002 普及组] 级数求和

题目内容 已知&#xff1a;Sn​121​31​…n1​。显然对于任意一个整数 k&#xff0c;当 n 足够大的时候&#xff0c;Sn​>k。 现给出一个整数 k&#xff0c;要求计算出一个最小的 n&#xff0c;使得 Sn​>k。 输入格式 一个正整数 k。 输出格式 一个正整数 n。 样…

代码随想录DAY22 - 回溯算法 - 08/21

目录 理论回顾 什么是回溯法 回溯法的效率 回溯法解决的问题 如何理解回溯 组合 题干 思路和代码 递归法 递归优化&#xff1a;剪枝 组合总和Ⅲ 题干 思路和代码 递归法 递归优化 电话号码的字母组合 题干 思路和代码 递归法 理论回顾 什么是回溯法 回溯是…