代码编织梦想

目录

信号机制原理:

信号的产生方式:

常用信号:

 信号相关命令kill/killal

 信号发送 -Kill/raise

 定时器函数

 alarm/pause

int pause(void)

信号的捕捉

过程: 

 signal函数

sigaction函数:

定时器

alarm

setitimer

SIGCHLD 回收子进程

信号集、信号的阻塞

信号集操作函数

sigprocmask

pause

 sigsuspend


信号机制原理:

        信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式;linux内核通过信号通知用户进程,不同的信号类型代表不同的事件;linux对早期的unix信号机制进行了扩展。

进程对信号有不同的响应方式:缺省方式;忽略信号;捕捉信号。

信号的产生方式:

 

常用信号:

 

 信号相关命令kill/killal

 信号发送 -Kill/raise

#include <unistd.h>  
#include <signal.h>
int kill(pid_t pid, int sig);
int raise(int sig);  //给自己发信号

 定时器函数

 alarm/pause

 int alarm (unsigned int seconds);
  • 成功时返回上个定时器的剩余时间,失败时返回EOF
  • seconds定时器的时间
  • 一个进程中只能设定一个定时器,时间到产生SIGALRM

int pause(void)

暂停

  • 进程一直阻塞,直到被信号中断
  • 被信号终端后返回-1,errno为EINTR   

信号的捕捉

过程: 

  1. 定义新的信号的执行函数handle。
  2. 使用signal/sigaction函数,把自定义的handle和指定的信号相关联。

 signal函数

 头文件: typedef void (*sighandler_t)(int); 
sighandler_t  signal(int signum, sighandler_t handler); 

功能:捕捉信号执行自定义函数

返回值:成功时返回原先的信号处理函数,失败时返回SIG_ERR(写入新的行为,返回旧的行为)

signum 要设置的信号类型

handler 指定的信号处理函数: SIG_DFL代表缺省方式; SIG_IGN 代表忽略信号;

 系统建议使用sigaction函数,因为signal在不同类unix系统的行为不完全一样。

sigaction函数:

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
结构体:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}

 

参数:

signum:处理的信号

act,oldact: 处理信号的新行为和旧的行为,是一个sigaction结构体。

sigaction结构体成员定义如下:

sa_handler:是一个函数指针,其含义与 signal 函数中的信号处理函数类似

sa_sigaction:另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。

sa_flags参考值如下:

SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数

SA_RESTART:使被信号打断的系统调用自动重新发起。

SA_RESETHAND:信号处理之后重新设置为默认的处理方式。

SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。

re_restorer:是一个已经废弃的数据域

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
	printf("i cath the SIGINT \n");
//	signal(SIGINT,oldact);
}

int main(){
    //填结构体内容
	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;
    //清空内容
    sigemptyset(&act.sa_mask);
    
	sigaction(SIGINT,&act,NULL);


	while(1){
		sleep(1);
	}
}

定时器

alarm

unsigned int alarm(unsigned int seconds);

功能:定时发送SIGALRM给当前进程

setitimer

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

功能:定时的发送alarm信号

参数:int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

功能:定时的发送alarm信号

参数:

which:

· ITIMER_REAL:以逝去时间递减。发送SIGALRM信号

· ITIMER_VIRTUAL: 计算进程(用户模式)执行的时间。发送SIGVTALRM信号

· ITIMER_PROF: 进程在用户模式(即程序执行时)和核心模式(即进程调度用时)均计算时间。发送SIGPROF信号

new_value: 负责设定 timout 时间

old_value: 存放旧的timeout值,一般指定为NULL

struct itimerval {

struct timeval it_interval; // 闹钟触发周期

struct timeval it_value; // 闹钟触发时间

};

struct timeval { //结构体里的结构体

time_t tv_sec; /* seconds */

suseconds_t tv_usec; /* microseconds */

};

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>
#include <sys/time.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
	if(sig == SIGINT)
	{
		printf("i cath the SIGINT \n");
	}
	else if (sig==SIGALRM)
	{
		printf("second timer \n");
//		alarm(1);
	}
//	signal(SIGINT,oldact);
}

int main(){
	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;

       	sigemptyset(&act.sa_mask);

	sigaction(SIGINT,&act,NULL);
//	alarm(1);
//	
	struct itimerval timevalue;
    //触发周期
	timevalue.it_interval.tv_sec = 1;
	timevalue.it_interval.tv_usec = 0;
    //触发时间
	timevalue.it_value.tv_sec = 5;
    timevalue.it_value.tv_usec = 0;


	setitimer(ITIMER_REAL, &timevalue, NULL);

	sigaction(SIGALRM,&act,NULL);

	while(1){
//		sleep(1);
	}
}

SIGCHLD 回收子进程

 

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

void handle(int sig){
	wait(NULL);
	printf("Get sig = %d\n",sig);
}

int main(){
	pid_t pid;
	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);

	pid = fork();

	if(pid>0){
		//wait(NULL); 父进程
		sigaction(SIGCHLD,&act,NULL);
		while(1){
			printf("this is father process\n");
			sleep(1);
		}
	} //子进程
    else if(pid == 0){
		sleep(3);
		exit(0);
	}

}

信号集、信号的阻塞

有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数,这种情况可以通过阻塞信号实现。

信号的阻塞概念:信号的”阻塞“是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生。

信号的状态:

        信号递达(Delivery ):实际信号执行的处理过程(3种状态:忽略,执行默认动作,捕获)

        信号未决(Pending):从产生到递达之间的状态

信号集操作函数

sigset_t set; 自定义信号集。 是一个32bit 64bit 128bit的数组。

sigemptyset(sigset_t *set); 清空信号集

sigfillset(sigset_t *set); 全部置1

sigaddset(sigset_t *set, int signum); 将一个信号添加到集合中

sigdelset(sigset_t *set, int signum); 将一个信号从集合中移除

sigismember(const sigset_t *set,int signum); 判断一个信号是否在集合中。

设定对信号集内的信号的处理方式(阻塞或不阻塞)

sigprocmask

#include <signal.h>

int sigprocmask( int how, const sigset_t *restrict set, sigset_t *restrict oset );

返回值:若成功则返回0,若出错则返回-1

首先,若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回。

其次,若set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。

how可选用的值:(注意,不能阻塞SIGKILL和SIGSTOP信号)

SIG_BLOCK : 把参数set中的信号添加到信号屏蔽字中

SIG_UNBLOCK:从信号屏蔽字中删除参数set中的信号

SIG_SETMASK:把信号屏蔽字设置为参数set中的信号

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

void handle(int sig){

	printf("I get sig=%d\n",sig);
}

int main(){
	struct sigaction act;
	act.sa_handler = handle;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGINT,&act,NULL);
//--------------------
	sigset_t set;  //自定义信号集
	sigemptyset(&set); //清空信号集
	sigaddset(&set,SIGINT); //  将一个信号添加到集合中

	sigprocmask(SIG_BLOCK,&set,NULL); // 屏蔽
	sleep(5);
	sigprocmask(SIG_UNBLOCK,&set,NULL); // 解除 屏蔽

	while(1){
		sleep(1);
	}

}

pause

int pause(void);

进程一直阻塞,直到被信号中断,

返回值:-1 并设置errno为EINTR

函数行为:

        1如果信号的默认处理动作是终止进程,则进程终止,pause函数么有机会返回。

        2如果信号的默认处理动作是忽略,进程继续处于挂起状态,pause函数不返回

        3 如果信号的处理动作是捕捉,则调用完信号处理函数之后,pause返回-1。

        4 pause收到的信号如果被屏蔽,那么pause就不能被唤醒

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

void handle(int sig){

	printf("I get sig=%d\n",sig);
}

void mytask(){
	printf("My task start\n");
	sleep(3);
	printf("My task end\n");

}

int main(){

	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);
	sigaction(SIGINT,&act,NULL);
	sigaction(SIGHUP,&act,NULL);
    
//屏蔽
    sigset_t set;
    sigaddset(&set,SIGHUP);
    sigaddset(&set,SIGINT);

	pause();
	while(1){
        sigprocmask(SIG_BLOCK,&set,NULL); //防止中断
		mytask();
        sigprocmask(SIG_UNBLOCK,&set,NULL);
		pause();
	}
	printf("After pause\n");
	while(1){

		sleep(1);
	}

}

 sigsuspend

int sigsuspend(const sigset_t *sigmask);

功能:将进程的屏蔽字替换为由参数sigmask给出的信号集,然后挂起进程的执行

参数:

sigmask:希望屏蔽的信号

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

void handle(int sig){

	printf("I get sig=%d\n",sig);
}

void mytask(){
	printf("My task start\n");
	sleep(3);
	printf("My task end\n");

}

int main(){

	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);
	sigaction(SIGINT,&act,NULL);
	sigaction(SIGHUP,&act,NULL);
    
//屏蔽
    sigset_t set,set2;
    sigemptyset(&set2);
    sigaddset(&set,SIGHUP);
    sigaddset(&set,SIGINT);

	pause();
	while(1){
        sigprocmask(SIG_BLOCK,&set,NULL); //防止中断
		mytask();
   //   sigprocmask(SIG_UNBLOCK,&set,NULL);
   //	pause();
        sigsuspend(&set2); //接收我们在任务执行过程中 执行的屏蔽掉的任务
	}
	printf("After pause\n");
	while(1){

		sleep(1);
	}

}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/super8ayan/article/details/127992386

十四、linux系统编程-信号(一)中断、信号、中断和信号-爱代码爱编程

一、中断 (1)、中断概念       中断是用以提高计算机工作效率、增强计算机功能的一项重要技术。最初引入硬件中断,只是出于性能上的考量。如果计算机系统没有中断,则处理器与外部设备通信时,它必须在向该设备发出指令后进行忙等待(Busy waiting),反复轮询该设备是否完成了动作并返回结果。这就造成了大量处理器周期被浪费。引入中断以

linux系统编程之信号(一):中断与信号-爱代码爱编程

一,什么是中断? 1.中断的基本概念 中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后又返回原来被中断处继续执行或调度新的进程执行的过程。引起中断发生的事件被称为中断源。中断源向CPU发出的请求中断处理信号称为中断请求,而CPU收到中断请求后转到

linux 高级编程 - 信号量 semaphore_cdevelopr的博客-爱代码爱编程

信号量 semaphore 信号量(semaphore)与之前介绍的管道,消息队列的等 IPC 的思想不同,信号量是一个计数器,用来为多个进程或线程提供对共享数据的访问。 信号量的原理 常用的信号量是二值信号量,它控制

linux 系统编程之-程序设计_王道长的编程之路的博客-爱代码爱编程_linux程序设计

文章目录 第1章 入门1.2.1 linux程序1.2.2 C语言编译器1.2.3 开发系统导引 第2章 shell程序设计2.3 什么是shell2.4 管道和重定向2.4.1 重定向输入2.4.3

[Linux系统编程]信号(三)-爱代码爱编程

       距离上一次利用高并发技术实现360度行车记录仪功能已经过去半年了。开始写一系列关于系统编程和网络编程内容进行总结。        温故而知新,欢迎大家讨论学习。10-06 复习时间 文章目录 1 信号的概念2 信号的共性3 信号的机制4 与信号相关的事件和状态5 信号四要素6 Linux常规信号汇总7 信号的产生7.1 终

Linux系统编程 97 信号的概念和机制-爱代码爱编程

学习笔记 信号的概念 信号在我们的生活中随处可见,如:古代战争中的摔杯为号;现代战争中的信号弹;体育比赛使用的信号枪... 共性: 1. 简单 2.不能携带大量信息 3.满足某个特设条件才发送 信号是信息的载体,linux/unix环境下,古老、经典的通信方式,现在依然是主要的通信手段。 unix早期就提供了信号机制,但是不可靠,信号可能会丢失。Be

linux系统编程 -爱代码爱编程

Linux 信号 Linux中,信号其实是软件中断,也是进程间通信的最古老的方式。它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个