Linux学习记录(十三)----信号

news2024/9/30 9:26:39

文章目录

      • 6.信号
        • 1.信号的发送(发送信号进程)
          • kill:
          • raise:
          • alarm :
        • 2.信号的接收
        • 3.信号的处理
        • 信号父子进程间通信
      • 7.信号灯(semaphore)
          • 创建信号灯函数
          • 控制信号灯函数
          • PV操作


声明:本人撰写的为学习笔记内容来源于网络,如有侵权联系删除(包括之前的文章)

6.信号

信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。

信号已经存在在内核中,不需要用户自己创造!

信号只能内核发!

内核可以发送多少种信号呢?

命令:kill ‐l
在这里插入图片描述

信号名含义默 认 操 作
SIGHUP该信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束 时,通知同一会话内的各个作业与控制终端不再关联。终 止
SIGINT该信号在用户键入INTR字符(通常是Ctrl-C)时发出,终端驱动程序发送此信号并送到 前台进程中的每一个进程。终 止
SIGQUIT该信号和SIGINT类似,但由QUIT字符(通常是Ctrl-)来控制。终 止
SIGILL该信号在一个进程企图执行一条非法指令时(可执行文件本身出现错误,或者试图执 行数据段、堆栈溢出时)发出。终 止
SIGFPE该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误,还包括溢出 及除数为0等其它所有的算术的错误。终 止
SIGKILL该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略。终 止
SIGALRM该信号当一个定时器到时的时候发出。终 止
SIGSTOP该信号用于暂停一个进程,且不能被阻塞、处理或忽略。暂 停 进 程
SIGTSTP该信号用于暂停交互进程,用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号。暂 停 进 程
SIGCHLD子进程改变状态时,父进程会收到这个信号忽 略
SIGABORT该信号用于结束进程终 止

信号通信的框架

  • 信号的发送(发送信号进程):kill、raise、alarm

  • 信号的接收(接收信号进程) : pause()、 sleep、 while(1)

  • 信号的处理(接收信号进程) :signal

1.信号的发送(发送信号进程)
kill:
#include<signal.h>
#include<sys/types.h>
函数原型:int kill(pid_t pid, int sig);
/*参数:
*		函数传入值:pid
*				正数:要接收信号的进程的进程号
*				  0:信号被发送到所有和pid进程在同一个进程组的进程
*				 ‐1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
*			sig:信号
*			函数返回值:成功 0 出错 ‐1
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc ,char *argv[])
{
	int sig;
	pid_t pid;
	if(argc > 3)
	{
		printf("param error\n");
		return -1;
	}
	sig = atoi(argv[1]);//将其转化成int类型的值
	pid = atoi(argv[2]);//将其转化成int类型的值
	printf("sig = %d,pid = %d\n",sig,pid);
	kill(pid,sig);//向进程号为pid的进程发送 sig信号
	return 0;
}

在这里插入图片描述

raise:

发信号给自己 == kill(getpid(), sig)

#include<signal.h>
#include<sys/types.h>
函数原型:
int raise(int sig);
/*参数:
* 	 函数传入值:sig:信号:
*@return 成功 0 出错 ‐1
*/
#include <stdio.h>
#include <stdlib.h>
#include<signal.h>
#include<sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
	pid_t pid;
	pid = fork();

	if(pid == -1)
	{
		printf("create process failed\n");
		return -1;
	}
	else if(pid > 0)
	{
		sleep(8);
		if(waitpid(pid,NULL,WNOHANG) == 0)//WNOHANG设置非阻塞,等于0表示子进程正在运行
		{
			kill(pid,9);
		}
		wait(NULL);
		while(1);	
	}
	else if(pid == 0)
	{
		printf("before raise\n");
		raise(SIGTSTP);//暂停信号
		printf("after raise\n");
	}
	return 0;
}
alarm :

发送闹钟信号的函数

alarm 与 raise 函数的比较:

相同点:让内核发送信号给当前进程

不同点:

  • alarm 只会发送SIGALARM信号

  • alarm 会让内核定时一段时间之后发送信号, raise会让内核立刻发信号

#include <unistd.h>
函数原型 unsigned int alarm(unsigned int seconds)
/*参数:
*		seconds:指定秒数
*@return:成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则 返回上一个闹钟时间的剩余时间,否则返回0。
*		  出错:‐1
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        int i = 0;
        alarm(7);
        while(1)
        {
                i++;
                printf("i = %d\n",i);
                sleep(1);
        }
        return 0;
}
2.信号的接收

接收信号的进程,要有什么条件:要想使接收的进程能收到信号,这个进程不能结束 :

sleep 、pause:进程状态为S

函数原型 int pause(void);
函数返回值 成功:0,出错:‐1
3.信号的处理

收到信号的进程,应该怎样处理? 处理的方式:

  • 1.进程的默认处理方式(内核为用户进程设置的默认处理方式)

    A:忽略B:终止进程C: 暂停

  • 2.自己的处理方式:

    自己处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的的处理方式

#include <signal.h>
函数原型 void (*signal(int signum, void (*handler)(int)))(int);
/*参数:
 *	signum:指定信号
 *	handler
 *	SIG_IGN:忽略该信号。
 *	SIG_DFL:采用系统默认方式处理信号
		自定义的信号处理函数指针
 *@return:成功:设置之前的信号处理方式,出错:‐1
	signal 函数有二个参数,第一个参数是一个整形变量(信号值),第二个参数是一个函数指针,是我们自己写的处理函
数;这个函数的返回值是一个函数指针。
 */

用自己定义的处理方式处理闹钟信号

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

void myalarm(int signum)
{
	int j = 3;
	printf("Processing of signal %d\n",signum);
	while(j--)
	{
		printf("get up!!!\n");
		sleep(1);
	}
}

int main()
{
	int i = 0;
	signal(14,myalarm);//信号处理函数收到对应的信号会执行自定义的函数
	printf("Please wake me up in 7 seconds\n");
	alarm(7);
	while(1)
	{
		i++;
		printf("i = %d\n",i);
		sleep(1);
		if(i > 7)
		{
			printf("I'm awake\n");
			break;
		}
	}
	return 0;
}

在这里插入图片描述

信号父子进程间通信

让父进程或子进程收到信号后执行一些特定的操作为信号父子进程间的通信

问题:

通信过程中子进程退出父进程无法收到子进程退出状态会导致子进程变成僵尸态

解决思路:

exit(0)== kill(pid,17);

父子进程间的通信

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

void myuser(int signum)
{
	int j = 3;
	printf("Processing of signal %d\n",signum);
	while(j--)
	{
		printf("Mom is back, go do some housework quickly\n");
		sleep(1);
	}
}

void mywait(int signum)
{
	printf("Processing of signal %d\n",signum);
	printf("Hurry up, Mom is very angry\n");
	wait(NULL);
}
int main()
{
	pid_t pid;
	pid = fork();
	int i = 0;
	if(pid == -1)
	{
		printf("create process failed\n");
		return -1;
	}
	if(pid > 0)
	{
		signal(10,myuser);//接收到信号执行操作
		signal(17,mywait);//接收到信号执行操作,防止子进程变成僵尸进程
		while(1)
		{
			printf("i = %d\n",i);
			i++;
			sleep(1);
			if(i > 10 && i < 15)
			{
				printf("I'm going now\n");
			}
			else if(i > 15)
			{
				printf("Son, dad ran away first\n");
				break;
			}
		}

	}
	else if(pid == 0)
	{
		sleep(10);
		kill(getppid(),10);
		sleep(5);
		exit(0);//kill(getppid(),17)
	}

	return 0;
}

在这里插入图片描述

7.信号灯(semaphore)

信号灯集合(可以包含多个信号灯)IPC对象是一个信号的集合(多个信号量)

创建信号灯函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型: int semget(key_t key, int nsems, int semflg);
//创建一个新的信号量或获取一个已经存在的信号量的键值。
/*
 *@param:
 *		key:和信号灯集关联的key值
 *		nsems: 信号灯集中包含的信号灯数目
 *		semflg:信号灯集的访问权限
 *@return:成功:信号灯集ID,出错:‐1
 */
控制信号灯函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型:int semctl ( int semid, int semnum, int cmd,…union semun arg(不是地址));
//控制信号量,删除信号量或初始化信号量

/*
 *@param:
 *		semid:信号灯集ID
 *		semnum: 要修改的信号灯编号
 *		cmd :
 *			GETVAL:获取信号灯的值
 *			SETVAL:设置信号灯的值
 *			IPC_RMID:从系统中删除信号灯集合
 *@return:
成功:0
出错:‐1

创建一个信号灯集合并删除它

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main()
{
        int semid;
        semid = semget(IPC_PRIVATE,3,0777);
        if(semid == -1)
        {
                printf("create semaphore failed\n");
                return -1;
        }
        printf("create semaphore successed semid is %d\n",semid);
        system("ipcs -s");
        semctl(semid,0,IPC_RMID);
        system("ipcs -s");
        return 0;
}

在这里插入图片描述

PV操作

P操作:申请资源操作

V操作:释放资源操作

在这里插入图片描述
include<sys/sem.h>
int semop(int semid ,struct sembuf sops ,size_t nsops);
//用户改变信号量的值。也就是使用资源还是释放资源使用权
/

*@param:

  •  semid : 信号量的标识码。也就是semget()的返回值
    
  •  sops是一个指向结构体数组的指针。
    
  •  	struct sembuf{
    
  •  					unsigned short sem_num;//信号灯编号;
    
  •  					short sem_op;//对该信号量的操作。‐1 ,P操作,1 ,V操作
    
  •  					short sem_flg;0阻塞,1非阻塞
    
  •  			     };
    
  •  nsops : 操作信号灯的个数
    

*//如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负
*数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用
*权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
*/

用信号灯pv操作读写共享内存

#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define SEM_READ 0
#define SEM_WRITE 0

union semun 
{
	int val;
};

void Poperation(int semnum,int semid)
{
	struct sembuf sop;
	sop.sem_num = 0;
	sop.sem_op = -1;//
	sop.sem_flg = 0;

	semop(semid,&sop,1);
}

void Voperation(int semnum,int semid)
{

	struct sembuf sop;
	sop.sem_num = 0;
	sop.sem_op = 1;
	sop.sem_flg = 0;

	semop(semid,&sop,1);
}
int main()
{
	int semid;
	int shmid;
	key_t key;
	char * shmaddr;
	key = ftok(".",123);
	semid = semget(key,3,IPC_CREAT|0777);
	if(semid == -1)
	{
		perror("semget");
		return -1;
	}
	shmid = shmget(key,128,IPC_CREAT|0777);
	if(shmid == -1)
	{
		perror("shmget");
		return -1;
	}	
	//init union
	union semun myun;
	//init semphore read
	myun.val = 0;
	semctl(semid,SEM_READ,SETVAL,myun);//设置读操作的value为0
	//init semphore write
	myun.val = 1;
	semctl(semid,SEM_WRITE,SETVAL,myun);

	pid_t pid = fork();
	if(pid == 0)
	{
		while(1)
		{
			shmaddr = (char *)shmat(shmid,NULL,0);//获取共享内存映射的地址
			Poperation(SEM_READ,semid);	//p操作通过判断是否有资源运行别的进程即若有别的进程在运行就会阻塞
			printf("get share memory is %s\n",shmaddr);
			Voperation(SEM_READ,semid);//释放资源,让别的进程操作可执行
		}
	}
	else if(pid > 0)
	{
		while(1)
		{
			shmaddr = (char *)shmat(shmid,NULL,0);//获取共享内存映射地址
			Poperation(SEM_WRITE,semid);
			printf("plese input message:\n");
			fgets(shmaddr,32,stdin);//从终端读到共享内存的映射中去
			Voperation(SEM_WRITE,semid);

		}
	}
	return 0;
}

疑问点:为什么连续给同一个信号量赋值之后,父子进程依旧可以调用读或写对应的val

在这里插入图片描述

解决:设置之后立马执行

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

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

相关文章

SQL Server中如何自动抓取阻塞

背景 当发数据库生阻塞时&#xff0c;可以通过SQL语句来获取当前阻塞的会话情况&#xff0c;可以得到下面的信息 说明&#xff1a;会话55阻塞了会话53。两个会话都执行了update test set fid10 where fid0。 但我们也经常碰到客户生产环境出现阻塞&#xff0c;由于不会抓取或者…

YOLOv8实现任意目录下命令行训练

问题 当你使用YOLOv8命令行训练模型的时候&#xff0c;如果当前执行的目录下没有相关的预训练模型文件&#xff0c;YOLOv8就会自动下载模型权重文件。这个是一个正常操作&#xff0c;但是你还会发现&#xff0c;当你在参数model中指定已有的&#xff0c;在其他目录下的预训练模…

实际案例:某日化集团主数据建设项目

一、建设背景1. 背景分析当前&#xff0c;该日化企业集团的主数据尚处于分散状态&#xff0c;分布于各业务系统中&#xff0c;缺乏一套专业的主数据管理系统进行统一管理。因此&#xff0c;数据无法在全集团范围内共享使用&#xff0c;且在业务端到端的流程拉通时&#xff0c;数…

WPS关闭后,进程依然在后台运行的解决办法

问题 wps启动后 在启动wps后&#xff0c;什么都不做&#xff0c;打开进程管理器&#xff0c;发现居然运行了3个wps进程&#xff1a; win10只会显示wps进程&#xff1a; win11显示比较准确&#xff1a; 关闭后 在关闭wps&#xff0c;再去任务管理器查看&#xff0c;发现在…

游戏开发设计模式之策略模式

目录 策略模式在游戏开发中的具体应用案例有哪些&#xff1f; 如何在Unity中实现策略模式以优化角色行为和AI策略&#xff1f; 策略模式与其他设计模式&#xff08;如观察者模式、状态模式&#xff09;在游戏开发中的比较优势是什么&#xff1f; 策略模式的优势 观察者模式…

基于SpringBoot的闲一品交易平台

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 Java技术 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 管理员…

【手撕OJ题】——160. 相交链表

目录 &#x1f552; 题目⌛ 方法① - 遍历记录链表长度⌛ 方法② - 双指针 &#x1f552; 题目 &#x1f50e; 160. 相交链表【难度&#xff1a;简单&#x1f7e2;】 &#x1f50e; 面试题 02.07. 链表相交 &#x1f50e; 剑指 Offer 52. 两个链表的第一个公共节点 给你两个单…

hadoop集成spark(spark on yarn)

文章目录 hadoop集成spark&#xff08;spark on yarn&#xff09;下载spark软件包spark文件设置spark-env.shworkers 环境变量设置发送spark到其余机器启动spark hadoop集成spark&#xff08;spark on yarn&#xff09; 在hadoop搭建完成的前提下&#xff0c;集成spark&#x…

【面试题系列Vue02】Vue Router 路由都有哪些模式?各模式之间有什么区别?

官方解析 Vue Router 路由有三种模式&#xff1a; hash 模式&#xff1a;使⽤ URL 中的 hash&#xff08;即 # 后面的内容&#xff09;来作为路由路径。 在这种模式下&#xff0c;页面不会重新加载&#xff0c;只会更新 hash 值&#xff0c;并触发路由变化&#xff0c;从而渲…

c语言杂谈系列:模拟虚函数

从整体来看&#xff0c;笔者的做法与之前的模拟多态十分相似&#xff0c;毕竟c多态的实现与虚函数密切相关 废话少说&#xff0c;see my code&#xff1a; kernel.c#include "kernel.h" #include <stdio.h>void shape_draw(struct shape_t* obj) {/* Call dr…

气膜粮仓:卓越的抗风雪能力与高性能材料—轻空间

在粮食储存领域&#xff0c;气膜粮仓以其卓越的抗风雪能力和高性能材料成为了现代农业的首选。其独特的设计和先进的材料使其在各种极端天气条件下依然能够保证粮食的安全和品质。 强抗风雪能力&#xff0c;保障粮仓安全 气膜粮仓采用了创新的结构设计&#xff0c;能够有效抵御…

Selenium + Python 自动化测试19(补充-读取各种文件数据操作)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了数据驱动测试中如何完成重复的测试实例&#xff0c;今天我们补充一些读取各种文件的方法。 本篇文章我们讨论一下如何使用读取txt、CSV、Excel文件&#xff0…

burpsuite xssValidator插件(xss插件)

安装 1. 商城安装插件 2. 安装环境 Download PhantomJShttps://phantomjs.org/download.htmlGitHub - NetSPI/xssValidator: This is a burp intruder extender that is designed for automation and validation of XSS

halcon1

Halcon安装&#xff1a;halcon介绍&#xff1a; 德国MVtec公司开发的一套完善的标准的机器视觉算法包。底层功能算法多&#xff0c;运算性能快。halcon不能提供相应的界面编程需求&#xff0c;需要和vs一起才能构成一套完整软件。 软件界面 halcon数据类型 Halcon的数据类型主…

Hugo博客搭建

Hugo 构建 Hugo 安装 下载 安装包hugo version 查看是否安装成功 生成站点基础框架 进入自己指定文件夹下执行 hugo new site solejay-blog创建仓库 cd solejay-blog git init主题配置 进入 Hugo 主题页面 选择主题并下载 个人喜欢的主题&#xff1a;meme、newsroom、gal…

mac安装java17(jdk17)

1. 下载jdk17 官网下载&#xff1a;https://www.oracle.com/java/technologies/downloads 2. 直接安装 安装完后目录会存放在下面目录下 /Library/Java/JavaVirtualMachines 111111deMBP JavaVirtualMachines % ls jdk-11.0.227 jdk-17.jdk 3. 如果你已经安装过java&#…

【MobaXterm】查找输出结果的关键字

要求&#xff1a; 在MobaXterm终端的输出结果 查找关键字 解决&#xff1a; 菜单栏终端->在终端中查找 Terminal -> Find in terminal

智慧水务项目(七)vscode 远程连接ubuntu 20.04 服务器,调试pyscada,踩坑多多

一、说明 以前用过pycharm&#xff0c;远程连接还可以&#xff0c;但是vscode用以前还可以&#xff0c;就用它开发python了&#xff0c;想搞个远程&#xff0c;源码直接放服务器上&#xff0c;能远程调试&#xff0c;其实也很方便的&#xff0c;结果第一次还成功了&#xff0c;…

【机器翻译方向】数据集合集!

本文将为您介绍经典、热门的数据集&#xff0c;希望对您在选择适合的数据集时有所帮助。 1 QUAK 发布方&#xff1a; Upstage高丽大学 发布时间&#xff1a; 2022 韩英合成机器翻译质量预测数据 (韩英神经机器翻译的一个合成质量估计数据集&#xff0c;QUAK) 是指韩语句子和…

erlang学习:erlang学习:书上案例22.6练习题3

初步实现了书上案例第二&#xff0c;三问的要求&#xff0c;对输出结果有部分偏差&#xff0c;没有实现对已完成任务状态的记录&#xff0c;因此已完成任务输出无论如何都是0&#xff0c;明天会在record中加一个字段进行已完成任务状态的记录 (2) 添加一个名为job_centre:stati…