22、linux信号学习(1)
1、最简单的安装信号
示例1
#include <iostream>
using namespace std;
#include <signal.h>
void func(int sig)
{
cout<<"用户自定义"<<endl;
}
int main()
{
signal(SIGUSR1,func);
pid_t pid = getpid();
kill(pid, SIGUSR1);/*用户自定义信号,kill具有发信号的功能,这行代码向“自身进程pid发信号SIGUSR1,执行的最终结果是触发SIGUSR1信号*/
}
2、更高层软件形式的异常,称为unix信号,它允许进程中断其他进程。一个信号(signal)就是一条消息,它通知进程一个某种类型的事件已经在系统中发生了。Linux支持30种不同类型的信号。
调用kill函数可以向指定进程发出指定的信号,调用raise函数,可以使进程向自己发送指定的信号,alarm可以使进程向自己经过指定的秒数后发送SIGALRM信号。
① SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
② SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
③ SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。
sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现。
3、unix shell 使用作业(job)的抽象概念来表示求值一条命令行而产生的进程。在任何时刻,到多只有一个前台作业和0个或式个后台作业。shell为每个作业创建一个独立的进程组。
4、函数
1)alarm
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds 为0,则之前设置的闹钟会被取消,并将剩下的时间返回。
alarm示例
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void handler(int sig)
{
printf("hello\n");
}
int main()
{
int i;
signal(SIGALRM, handler);
alarm(5);
for (i = 0; i < 7; i++)
{
printf("sleep %d ...\n", i);
sleep(1);
}
return 0;
}
2)kill
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
The kill() system call can be used to send any signal to any process group or process.
kill()用来送指定的信号sig给参数pid指定的进程。参数pid有几种情况:
pid>0 将信号传给进程识别码为pid 的进程。
pid=0 将信号传给和目前进程相同进程组的所有进程
pid=-1 将信号广播传送给系统内所有的进程
pid<0 将信号传给进程组识别码为pid绝对值的所有进程
3)int pause(void);
pause()会令目前的进程暂停(进入睡眠状态),直到被信号(signal)所中断。
int raise(int sig);
//The raise() function sends a signal to the current process. It is equivalent to kill(getpid(), sig);
4)#include<signal.h>
int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的所有信号。
struct sigaction
{
void (*sa_handler) (int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);
}
① sa_handler参数和signal()的参数handler相同,代表新的信号处理函数;
② sa_mask 用来设置在处理该信号时暂时将sa_mask指定的信号搁置。sa_mask gives a mask of signals which should be blocked during execution of the signal handler. In addition, the signal which triggered the handler will be blocked, unless the SA_NODEFER flag is used.
③ sa_restorer 此参数没有使用。
④ sa_flags 用来设置信号处理的其他相关操作。OR运算(|)组合:
a. A_NOCLDSTOP : 如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程
b. SA_ONESHOT/SA_RESETHAND:当调用信号处理函数前,将此信号处理方式改为缺省值;SA_RESETHAND是这个标记的正式的POSIX名字,为了软件的可移植性,一般不用SA_ONESHOT。
c. SA_RESTART:被信号中断的系统调用会自行重启
d. SA_NOMASK/SA_NODEFER:在处理此信号未结束前不理会此信号的再次到来。SA_NODEFER是这个标记的正式的POSIX名字,为了软件的可移植性,一般不用SA_NOMASK)
如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction 返回。
示例代码
#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <cstdio>
using namespace std;
void show_handler(int sig)
{
cout << "I got signal " << sig << endl;
for (int i = 0; i < 5; i++)
{
cout << "i = " << i << endl;
sleep(1);
}
}
int main()
{
int i;
struct sigaction act, oldact;
act.sa_handler = show_handler;
act.sa_flags = SA_RESETHAND | SA_NODEFER;
sigaddset(&act.sa_mask, SIGQUIT); //屏蔽ctrl+\信号
//sigaction(SIGUSR1, &act, &oldact);
sigaction(SIGINT, &act, &oldact);
while(1)
{
sleep(1);
cout << "sleeping " << i << endl;
i++;
//kill(getpid(), SIGUSR1); //通过kill,向当前进程进行发送信号SIGUSR1
}
}