linux用信号写代码,Linux学习笔记(10)-信号(示例代码)

所谓信号(singal),在我的理解来说,其实和单片机开发中的中断差不多,但是它并非是由系统硬件所提供的,而是软件操作系统的支持的一种提醒机制。

收到信号之后的处理方法,一般由三种:

(1)第一种是类似于中断处理函数,对于要处理的信号,进程指定某个处理函数。

(2)第二种是忽略某个信号,不做任何处理。

(3)第三种是使用系统默认的处理方式,比如Ctrl+c的终止当前进程。

Linux中常用的信号有30多种,每个信号都以关键字SIG开头,比如异常终止的信号,名叫SIGABRT。

在头文件《Singal.h》中,他们都被定义成整数。

下面有一些常用的信号量:

SIGALRM :使用定时器函数alarm()后,当定时时间到达时所产生的信号

SIGINT:当用户在终端使用Ctrl+c后产生的信号(如果对这个信号不做别的重定义,那么它的意义就是终止当前进程)

SIGKILL:这个信号是两个不能捕捉,不能忽略的信号之一,他的作用在于杀死某个进程

SIGSTOP:这个信号是两个不能捕捉,不能忽略的信号之一,他的作用在于停止某个进程

……

使用kill -l命令可以产看当前系统的所用信号量。

19ecc37be2f8400da6beb1232faa9ef8.jpg

信号如果使用在代码中,当然有对应的函数,比如函数:sigaction()这个函数就是用来重新定义,当信号产生时的处理方式……

在单片机编程中,有点像中断回调函数的登录!

函数sigaction函数的原形如下:

sigaction(int signum , const struct sigaction *act, struct sigaction *oldaction)

现在对参数进行讲解:

int signum :指定想要修改处理方式的信号,比如SIGINT,当用户在终端输出Ctrl + c后,我们可以改变它的处理,也就是不用终止当前进程

△正如上面所说,有两个信号的处理无法被用户改变,就是SIGKILL和SIGSTOP这两个信号,打死也改不了

act和oldact是相同类型的结构体,前者指定新的处理,后者是原来的处理方法。

那个sigaction结构体的原形如下:

3391231aca4f423c90d0b4a603afaae5.jpg

void(*sa_handler)(int)是一个函数指针,用来指定信号发生后的处理函数。

void (*sa_sigaction)(int,siginfo_t*,void*)也是用来指定信号发生后的处理函数……

至于在信号发生后,以上两个函数选择哪一个来使用,则取决于成员sa_flags.如果sa_flags的值中包含了SA_SIGINFO时,则使用第二个函数,否则使用第一个函数。

sa_mask成员用来指定在信号函数执行期间,需要被屏蔽的信号。

sa_flags成员用于指定信号处理的行为,它是下值的按位或组合 。

SA_RESTART:被信号打断的进程重启

SA_NOCLDSTOP:父进程在子进程暂停或继续运行时,不会收到SIGCHID信号。

解释:

在Linux的多进程编程中,SIGCLD是一个非常重要的信号。当一个子进程退出时,并不是立即释放其占用的资源,而是通知其父进程,由父进程进行后续的工作。

在这一过程中,系统将依次产生下列事件。

1)向父进程发送SIGCLD信号,子进程进入zombie(僵尸)状态。

2)父进程接收到SIGCLD信号,进行处理。

不过,我还是对这个信号有些不明白!

SA_NOCLDWAIT:父进程在子进程退出时,不会收到SIGCHID信号。这样子进程即使退出了,也不会形成僵尸进程

SA_NODEFER:信号的屏蔽无效,即使在中断服务函数处理中,任然能发出这个信号

SA_RESETHAND:在信号被处理过一次后,恢复系统本来的默认处理

SA_SIGINFO:指定信号发生后,是使用第一个函数还是第二个函数

——————————————————————————————————————————————————————

现在开始写代码,需求如下,当用户按下Ctrl+c后,系统并不会终止当前进程,而是答应出一句话,然后在按一次,这时才会终止进程。

#include#include#include

void handler(intsig)

{

printf("抓到一个Ctrl+C信号:%d.\\n",sig);return;

}int main(void)

{structsigaction act;

act.sa_handler= handler;//指定使用的信号服务函数

act.sa_flags = SA_RESETHAND;//设置信号复归模式

sigemptyset(&act.sa_mask);//清空屏蔽信号集

sigaction(SIGINT,handler,NULL);//重定义信号处理

while(1)

{//等待信号发生

printf("等待信号发生中!\\n");

sleep(1);

}return 0;

}

代码编写完毕,现在开始做makefile

好,这个也做完了!

现在执行编译命令!

56641a9a8c7c467c80be17a4c16aa1ac.jpg

一大堆警告,哎!!怎么办呢!!!

sigaction(SIGINT,&act,NULL);//原来是自己在这里写错了,把函数直接当成结构体了

修改后在编译……安全通过,执行代码。

结果如下:

0c108710ad574e169106be65f7353387.jpg

现在我按一下Ctrl+c,看看会发生什么。

b7689d03806340f38a44b6445cdb8493.jpg

进程并没有终止,而是按照我们的要求,输出了一句话。至于那个2代表的是什么意思?我现在还不知道……如果你知道,希望能告诉我一下。

然后我再次按下Ctrl+c,结果如下:

a2952d173d72466fa2e2864f07df0aac.jpg

进程果然停止了……

当然,如果修改一下代码,将系统默认处理重设的语句屏蔽掉,那么这个进程永远也不会停止了!

//act.sa_flags = SA_RESETHAND;//设置信号复归模式

…………

现在使用另一个信号,闹钟信号来实现一个功能,既,系统在休眠后,每隔3秒打印出当前的时间。

#include#include#include#include#include

void handler(intsig)

{

time_t curtime;

time(&curtime);

printf("现在时间:%s\\n",ctime(&curtime));

alarm(3);

}int main(void)

{

alarm(3);

signal(SIGALRM,handler);

printf("进入休眠!\\n");while(1)

{

sleep(1);

}return 0;

}

代码编写完毕,执行结果如下!

662ab05c3edf4732a695678df0b122ba.jpg

执行结果无误。

当然,这只是两个简单的信号,还有别的信号等改天再试,现在都快十一点了……明天还得上班!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值