Linux 系统编程-信号机制

目录

信号机制原理:

信号的产生方式:

常用信号:

 信号相关命令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);
	}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统编程训练营是CSDN(中国软件开发网)举办的面向开发人员的一项培训活动。本训练营旨在提供给开发者相关的Linux系统编程知识和技能,帮助他们更好地应用Linux系统进行开发。 在Linux系统编程训练营中,学员将学习到Linux操作系统的基本原理和核心技术。他们将了解Linux操作系统系统调用、进程管理、信号处理、文件系统以及网络编程等方面的知识。通过训练营的学习,学员将能够更深入地理解Linux系统的工作原理和运行机制,从而能够更好地利用Linux系统进行应用开发。 此外,Linux系统编程训练营还将提供实际的案例和项目,让学员进行实践和项目开发。通过实践,学员将能够巩固所学知识,并熟悉常见的Linux系统编程工具和技术,如GCC编译器、调试工具GDB等。这将帮助学员提升他们的Linux系统编程能力,并为他们未来的工作提供更多的实践经验和技能。 最后,Linux系统编程训练营还提供了实时交流和学习的机会。学员可以通过在线讨论、答疑和实验等形式,与讲师和其他学员进行交流和讨论。这将帮助学员更好地理解和掌握Linux系统编程相关的知识,同时也为他们提供了与其他开发者互动和学习的平台。 总结来说,Linux系统编程训练营是CSDN举办的一项针对开发人员的培训活动,通过系统化的课程和实践项目,帮助学员提升Linux系统编程的技能和能力。这不仅对于开发者个人的成长和发展有着重要意义,也对于推动社区的技术创新和发展具有积极的推动作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值