目录
- 信号的概念
- 信号函数分析
- 案例有两个
写在前面:下面注释有的有英文,并不是我翻译成英语的,是man文档的原句,后面的中文是我参考有关资料和自己分析的中文。
(一)信号的基本概念
- 信号全称为软中断信号,也有人称作软中断。可以看出,它的实质和使用很像中断。
- 软中断信号( signal,又简称为信号)用来通知进程发生了异步事件,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
- 三种处理行为:
第一种
类似中断的处理程序(a pointer to a signal handling function),对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
第二种
忽略(SIG_IGN)某个信号,对该信号不做任何处理,就象未发生过一样。
第三种
对该信号的处理保留系统的默认值(SIG_DFL),这种缺省操作,对大部分的信号的缺省操作是使得进程终止。
- 信号的分类–简单描述下
POSIX.1中提及的signal值(man 7 signal信息量很丰富,man手册要仔细阅读哦!!)。我保留英语,可以帮你快速理解。自己总结做成pdf的,找了好多资料。。。
注意:里面有好几个经常用到的
SIGINT、SIGQUIT、SIGKILL、SIGALRM、SIGSTOP、SIGCHLD、SIGPIPE、等,总之,信号是异步的,在操作系统中很重要
还有其他的信号就不用说了,如:SUSv2 。文档里有。。
等会有一个关于alarm例程:alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds—闹铃,和SIGALRM信号搭配使用,实现在设定闹铃时间发出信号
(二)信号操作流程
先介绍函数,涉及好多个。。 前面几个是比较重要的
(1)检查和更改信号操作
sigaction():examine and change a signal action
int sigaction(int signum, const struct sigaction *act ,struct sigaction *oldact);
参数分析:
- signum: 表示信号取值,就是上面的表的signal值。
- act: If act is non-NULL, the new action for signal signum is installed from act. If oldact is non-NULL, the previous action is saved in oldact.
如果act不空,新的act将存进,旧的act将存在oldact里
注意:这里涉及一个很重要的结构体
struct sigaction----描述信号到来所采取的动作
//Structure describing the action to be taken when a signal arrives.-描述信号到来所采取的动作
struct sigaction {
void (*sa_handler)(int); //SIG_DFL for the default action, SIG_IGN to ignore this signal, or a pointer to a signal handling function.
void (*sa_sigaction)(int, siginfo_t *, void *); //do not assign to both sa_handler and sa_sigaction
sigset_t sa_mask; //specifies a mask of signals which should be blocked
int sa_flags;//=0,如果系统调用被sig信号打断,则在处理完sig信号后,就会重新调用被打断的系统调用,这也是linux默认的行为。
void (*sa_restorer)(void); //obsolete过时了,不要再使用了
};
- (*sa_handler)(int) : 有三种行为,上面讲了哈!
- (*sa_sigaction)(int, siginfo_t *, void *): do not assign to both sa_handler and sa_sigaction—就是结构体里面的前两个不要都赋值。为什么呢?其实在sigaction.h中定义了。
位置 :/usr/include/bits/sigaction.h --里面还有其他参数,有兴趣可以仔细分析下,不然 man 2 sigaction看着有些吃力。
- sa_mask:specifies a mask of signals which should be blocked。你要屏蔽才有用哈
- sa_flags:这个都够写一篇博客了,感兴趣网上自己找下资料
- (*sa_restorer)(void): 过时了,不要研究了。
- 返回值: sigaction() returns 0 on success and -1 on error
如:
(2)设置屏蔽字
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
- how:–有三个常量值
SIG_BLOCK:The set of blocked signals is the union of the current set and the set argument.
SIG_UNBLOCK:The signals in set are removed from the current set of blocked signals
SIG_SETMASK:设置屏蔽字,将set中屏蔽字生效
这里设置ctrl+c屏蔽字 - 如果act不空,新的act将存进,旧的act将存在oldact里。act空,不做改变
- 返回值: sigprocmask() returns 0 on success and -1 on error
(3)测试信号是否被屏蔽
int sigpending(sigset_t *set);
- 返回值: sigpending() returns 0 on success and -1 on error
(4)测试是否加入信号集
int sigismember(const sigset_t *set, int signum);
- signum: 表示信号取值,就是上面的表的signal值。
- 返回值: 1 if signum is a member of set, 0 if signum is not a member, and -1 on error.
(5)删除信号集中的信号
int sigdelset(sigset_t *set, int signum);
- signum: 表示信号取值,就是上面的表的signal值。
- 返回值: return 0 on success and -1 on error.
(6)取消对SIGINT的屏蔽
int sigsuspend(const sigset_t *mask);
- 返回值: sigsuspend() always returns -1, normally with the error EINTR
(7)清空信号集
//清空信号集
int sigemptyset(sigset_t *set);
- set:信号集
- 返回值: return 0 on success and -1 on error.
(8)添加信号集
//添加信号集
int sigaddset(sigset_t *set, int signum);
- set:信号集
- signum: 表示信号取值,就是上面的表的signal值。
- 返回值: return 0 on success and -1 on error.
(8)休息等待信号的到来–和上面配合使用的
//causes the calling process(or thread)to sleep until a signal is delivered
int pause(void);
- 返回值: pause() only returns when a signal was caught and the signal-catching function returned. and -1 on error.
(三)案例一
闹铃:在正常延时7s的过程中,在第5s打印Hello world!!!(闹铃信号)
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
/****************************************************************************************
** 信号处理signal handling
** alarm():
** unsigned int alarm(unsigned int seconds);
** 描述:alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds
** 闹铃,和SIGALRM信号搭配使用,实现在设定闹铃时间发出信号
** RETURN VALUE
** the number of seconds remaining
** signal():
** sighandler_t signal(int signum, sighandler_t handler);
** signum :等待的信号
** handler:信号到来之后,触发的处理方式,如一个函数
** RETURN VALUE
** 成功返回0,错误返回-1
****************************************************************************************/
void handler()
{
printf("Hello world!!!\n");
}
//实验现象:在正常延时7s的过程中,在第5s打印Hello world!!!
int main(void)
{
int i = 1;
signal(SIGALRM, handler); //这里设置了一个闹钟,是在5s的时候运行handler函数,也就是打印Hello world!!!
alarm(5);
for(;i < 7; i++)
{
printf("Sleeping %d ...\n",i);
sleep(1);
}
}
输出:
案例二
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
/* //Structure describing the action to be taken when a signal arrives.-描述信号到来所采取的动作
struct sigaction {
void (*sa_handler)(int); //SIG_DFL for the default action, SIG_IGN to ignore this signal, or a pointer to a signal handling function.
void (*sa_sigaction)(int, siginfo_t *, void *); //do not assign to both sa_handler and sa_sigaction
sigset_t sa_mask; //specifies a mask of signals which should be blocked
int sa_flags;//=0,如果系统调用被sig信号打断,则在处理完sig信号后,就会重新调用被打断的系统调用,这也是linux默认的行为。
void (*sa_restorer)(void); //obsolete过时了,不要再使用了
}; */
/****************************************************************************************
** 信号处理signal handling
** sigaction():examine and change a signal action
** int sigaction(int signum, const struct sigaction *act ,struct sigaction *oldact);
** act:
** If act is non-NULL, the new action for signal signum is installed from act. If oldact is non-NULL, the previous action is saved in oldact.
如果act不空,新的act将存进,旧的act将存在oldact里
** 描述:alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds
** 闹铃,和SIGALRM信号搭配使用,实现在设定闹铃时间发出信号
** RETURN VALUE
** sigaction() returns 0 on success and -1 on error
** sigprocmask():
** int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
** SIG_SETMASK:设置屏蔽字,将set中屏蔽字生效
** 如果act不空,新的act将存进,旧的act将存在oldact里。act空,不做改变
** RETURN VALUE
** sigprocmask() returns 0 on success and -1 on error.
** sigpending(): examine pending signals--测试SIGINT是否被屏蔽
** int sigpending(sigset_t *set);
** RETURN VALUE
** sigpending() returns 0 on success and -1 on error.
** sigemptyset():Clear all signals from SET.
** int sigemptyset(sigset_t *set);
** RETURN VALUE
** sigemptyset() return 0 on success and -1 on error.
** sigismember():测试是否加入信号集
** int sigismember(const sigset_t *set, int signum);
** RETURN VALUE
** 1 if signum is a member of set, 0 if signum is not a member, and -1 on error.
** sigdelset():删除信号集中的信号
** int sigdelset(sigset_t *set, int signum);
** RETURN VALUE
** sigdelset() return 0 on success and -1 on error.
** sigaddset():set to full, including all signals-添加信号集
** int sigaddset(sigset_t *set, int signum);
** signum: 就是所有信号取值,上面的表
** RETURN VALUE
** sigaddset() return 0 on success and -1 on error.
** sigsuspend(): wait for a signal
** int sigsuspend(const sigset_t *mask);
** signum: 就是所有信号取值,上面的表
** RETURN VALUE
** sigaddset() return 0 on success and -1 on error.
** pause(): causes the calling process(or thread)to sleep until a signal is delivered
** int pause(void);
** RETURN VALUE
** pause() only returns when a signal was caught and the signal-catching function returned. and -1 on error.
****************************************************************************************/
//处理函数
void handler(int sig)
{
printf("Handl signal is %d!!!\n",sig);
}
int main()
{
sigset_t sigset; //记录屏蔽字
sigset_t ign; //记录被阻塞的信号集
struct sigaction act;
//清空信号集
sigemptyset(&sigset);
sigemptyset(&ign);
//添加信号集
sigaddset(&sigset, SIGINT); //SIGINT----CTRL+C
//设置处理函数及信号集----给结构体赋值
act.sa_handler = handler; //处理函数
sigemptyset(&act.sa_mask); //设置屏蔽
act.sa_flags = 0; //默认行为,
sigaction(SIGINT, &act, 0);
printf("Wait the signal SIGINT!!!\n");
pause(); //挂起进程,等待信号
//设置屏蔽字,SIGINT
sigprocmask(SIG_SETMASK, &sigset, 0); //将sigset的SIGINT生效
printf("Please press ctrl+c in 5 seconds!!!\n");
sleep(5);
//测试SIGINT是否被屏蔽
sigpending(&ign);
//测试是否加入信号集
if(sigismember(&ign, SIGINT))
{
printf("The SIGINT has ignored!!!\n");
}
//删除信号集中的信号
sigdelset(&sigset, SIGINT);
printf("Wait the signal SIGINT!!!\n");
//取消对SIGINT的屏蔽
sigsuspend(&sigset);
printf("App exit after 5 seconds!!!\n");
sleep(5);
return 0;
}
**输出:**里面输出的2,是SIGINT的值。