C语言中(void)signal(SIGALRM, alarmhandle);是什么意思

C语言中(void)signal(SIGALRM, alarmhandle);是什么意思,第1张

signal(SIGALRM, alarmhandle); 表示给当前进程注册SIGALRM信号处理代码,如果收到SIGALRM信号,就会去执行alarmhandle函数

$ man signal

SYNOPSIS

       #include <signalh>

       typedef void (sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

DESCRIPTION

       The  signal() system call installs a new signal handler for the signal with number signum  The signal handler is set to sighandler which may be a user specified function, or either SIG_IGN or SIG_DFL

       signal()函数是个系统调用,该函数按signum设定一个新的信号处理句柄(函数)新设定的处理函数可以是用户自定义的函数,也可以是系统指定的SIG_IGN 或 SIG_DFL

参考代码:

#include <signalh>

#include <unistdh>

#include <stdioh>

#include <stdlibh>

void alarmhandle(int sig)

{

    printf("recv sig:%d\n", sig );

    printf("exit!\n");

    exit(0);

}

int main()

{

    signal( SIGALRM, alarmhandle );

    printf("begin\n");

    alarm(5); //定时器,用于在5秒后产生SIGALRM信号

    while( 1 );

    return 0;

}

运行结果:

begin

recv sig:14

exit!

下面所指的signal都是指以前的older signal函数,现在大多系统都用sigaction重新实现了signal函数

1、signal在调用handler之前先把信号的handler指针恢复;sigaction调用之后不会恢复handler指针,直到再次调用sigaction修改handler指针。

:这样,(1)signal就会丢失信号,而且不能处理重复的信号,而sigaction就可以。因为signal在得到信号和调用handler之间有个时间把handler恢复了,这样再次接收到此信号就会执行默认的handler。(虽然有些调用,在handler的以开头再次置handler,这样只能保证丢信号的概率降低,但是不能保证所有的信号都能正确处理)

2、signal在调用过程不支持信号block;sigaction调用后在handler调用之前会把屏蔽信号(屏蔽信号中自动默认包含传送的该信号)加入信号中,handler调用后会自动恢复信号到原先的值。

(2)signal处理过程中就不能提供阻塞某些信号的功能,sigaction就可以阻指定的信号和本身处理的信号,直到handler处理结束。这样就可以阻塞本身处理的信号,到handler结束就可以再次接受重复的信号。

信号是与一定的进程相联系的。也就是说,一个进程可以决定在进程中对哪些信号进行什么样的处理。例如,一个进程可以忽略某些信号而只处理其他一些信号;另外,一个进程还可以选择如何处理信号。总之,这些总与特定的进程相联系的。因此,首先要建立其信号和进程的对应关系,这就是信号的安装登记。

Linux主要有两个函数实现信号的安装登记:signal和sigaction。其中signal在系统调用的基础上实现,是库函数。它只有两个参数,不支持信号传递信息,主要是用于前32个非实时信号的安装;而sigaction是较新的函数(由两个系统调用实现:sys_signal以及sys_rt_sigaction),有三个参数,支持信号传递信息,主要用来与sigqueue系统调用配合使用。当然,sigaction同样支持非实时信号的安装,sigaction优于signal主要体现在支持信号带有参数。

对于应用程序自行处理的信号来说,信号的生命周期要经过信号的安装登记、信号集 *** 作、信号的发送和信号的处理四个阶段。信号的安装登记指的是在应用程序中,安装对此信号的处理方法。信号集 *** 作的作用是用于对指定的一个或多个信号进行信号屏蔽,此阶段对有些应用程序来说并不需要。信号的发送指的是发送信号,可以通过硬件(如在终端上按下Ctrl-C)发送的信号和软件(如通过kill函数)发送的信号。信号的处理指的是 *** 作系统对接收信号进程的处理,处理方法是先检查信号集 *** 作函数是否对此信号进行屏蔽,如果没有屏蔽, *** 作系统将按信号安装函数中登记注册的处理函数完成对此进程的处理。

函数在C语言中是必不可少的一部分,大致可以分为两种:系统定义好的和我们自己写的。不管是哪种函数,它们都默默地、兢兢业业地完成着属于自己的任务。只要给它一些参数,它就会把参数处理好、有些函数还会把处理结果返回出来。以下几种特殊函数,你有见过吗?会用吗?

1、静态函数

普通的函数一般是全局的,可见范围是跨文件的,比如ac 这个文件中有一个函数名为 func() , bc文件 中是可以直接调用ac中的func函数的。而静态函数不同,它被static修饰之后可见范围缩小到本文件可见,其它文件不可见。

如果真的是闲得蛋疼想在一个文件中调用一个别的文件中的静态函数,也有办法:

1直接把func所在的函数包含进来 #include "bc"

2可以把static 修饰的函数写在头文件中

2、递归函数:

这个名字看起来有一点数学味,比较高级的样子。其实它的定义也很简单:在一个函数内部调用了自身,那这个函数就是递归函数。

下面写了一个例子:

使用递归函数的时候有几个问题要注意:

1只有能被递归解决的问题才可以使用递归来解决。(阶乘、幂运算、字符翻转等)

2递归函数中必须有一个可以直接退出(返回)的条件,否则会进入无限循环。

3递归的过程包含两个:逐渐递进,层层回归。

4递归函数会使用大量的栈内存空间,要注意递归的层次不要太深,如果一定要用的话可以尝试把栈空间的大小临时设置一下。(ulimit -s)

3指针函数

这种函数是什么其实很明显了,指针函数就是返回值是指针类型的函数。

使用的时候要确保该函数的返回值是指针,不然编译器会报警告。

4、回调函数

函数的实现方,它不方便直接调用该函数,而是由第三方接口来调用该函数,该函数就是回调函数。概念有点绕,我们直接看代码:

可以看到我们在主函数main里面并没有直接调用func()函数,而是运用函数指针P通过一个signal函数去调用它。在实际工程中回调函数会用得比较多,就像图中的signal函数,假设这个函数是从别人手上买回来的,我们无权访问其源码,只能够使用。卖家给我们留下了接口让我们使用它,因此我给了它两个参数,当它收到信号2的时候,我希望它能帮我调用我写的func()函数。那么func()就是所谓的回调函数。

5、内联函数

如果有一个函数被多次调用,那么该函数在调用过程中会消耗程序执行的时间, 而内联函数指的就是可以把需要调用的函数副本拷贝到调用者的内部,节约了调用过程中的时间。

普通函数的调用与切换过程:

内联函数示意图:

内联语法:

什么时候应该用内联函数:一个函数在另一个函数多次被调用,而且被调用函数的内容比较少的情况。

6、变参函数

如果一个函数的参数类型以及参数的数量都是可变的,那么这个函数就称之为变参函数(如我们常用的printf)。

函数形参在栈中分配内存的顺序,从右到左的独特顺序使得第一个参数是栈顶元素(即示例中的参数 format),我们就可以根据第一个已知的参数(绿色)所提供的线索, 来回溯剩下的未知的参数(**)

以上六种特殊函数,你看懂了吗?有任何疑问可以评论区告诉我哦!

森式嵌入,持续分享嵌入式硬知识。欢迎志同道合的朋友关注一起交流进步!

测试了一下,三个进程都会收到SIGINT信号。

原程序中,child1, child2都收到SIGINT信号,调用stop(), 之后被唤醒,打印"child process is killed by parent!",事实上kill这两个child的不是parent,是它们自己的SIGINT。

放到①处,child1收到SIGINT信号,默认的行为是把自己杀了,当然也来不及打印任何东西了。child2收到SIGINT信号,打断waiting(),打印"child process 2 ",然后退出。杀死它的也不是SIGUSR2信号。

放到②处,child1, child2收到SIGINT信号,默认的行为是立即把自己杀了,也来不及打印任何东西了。

测试方法:

// 打印谁执行、被什么信号打断

static void stop(int signal) {

printf("stop %d by signal %d\n", getpid(), signal);

wait_mark=0;

}

// 在parent进程中,打印各进程id

printf("parent %d, child1 %d, child2 %d\n",getpid(),p1,p2);

如果让parent成为杀死child的凶手,可以在child1,child2中加入:

signal(SIGINT, keep_me_alive);

// 不理睬SIGINT信号

static void keep_me_alive(int signal) {

}

这时打印结果就一样了

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/11677800.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-17
下一篇2023-05-17

发表评论

登录后才能评论

评论列表(0条)

    保存