信号(一)
一、kill –l产看所有的信号名,man 7 signal查看信号名及解释,man signal查看signal函数
二、中断分类
q 硬件中断(外部中断)
外部中断是指由外部设备通过硬件请求的方式产生的中断,也称为硬件中断
q 软件中断(内部中断)
内部中断是由CPU运行程序错误或执行内部程序调用引起的一种中断,也称为软件中断。
三、信号
q 信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。
q 信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等
q 信号是在软件层次上对中断的一种模拟,所以通常把它称为是软中断
四、信号与中断
q 信号与中断的相似点:
q (1)采用了相同的异步通信方式;
q (2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
q (3)都在处理完毕后返回到原来的断点;
q (4)对信号或中断都可进行屏蔽。
q 信号与中断的区别:
q (1)中断有优先级,而信号没有优先级,所有的信号都是平等的;
q (2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;
q (3)中断响应是及时的,而信号响应通常都有较大的时间延迟。
五、进程对信号的响应
q 忽略信号
不采取任何操作、有两个信号不能被忽略:SIGKILL和SIGSTOP。
q 捕获并处理信号
内核中断正在执行的代码,转去执行先前注册过的处
q 执行默认操作
默认操作通常是终止进程,这取决于被发送的信号。
六、signal
q typedef void (*__sighandler_t) (int);
q #define SIG_ERR ((__sighandler_t) -1)
q #define SIG_DFL ((__sighandler_t) 0)
q #define SIG_IGN ((__sighandler_t) 1)
q 函数原型:
__sighandler_t signal(int signum,__sighandler_t handler);
q 参数
q signal是一个带signum和handler两个参数的函数,准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数由handler给出
q handler这个函数必须有一个int类型的参数(即接收到的信号代码),它本身的类型是void
q handler也可以是下面两个特殊值:
SIG_IGN 屏蔽该信号
SIG_DFL 恢复默认行为
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
__sighandler_t oldhandler;
oldhandler = signal(SIGINT, handler);
if (oldhandler == SIG_ERR)
ERR_EXIT("signalerror");
while (getchar() != '\n')
;
/*
if (signal(SIGINT, oldhandler) ==SIG_ERR)
*/
if (signal(SIGINT, SIG_DFL) == SIG_ERR)
ERR_EXIT("signalerror");
for (;;) ;
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
}
信号(二)
一、信号的分类
可靠信号、不可靠信号、实时信号、非实时信号
二、信号发送
q kill
q raise
q 给自己发送信号。raise(sig)等价于kill(getpid(), sig);
q killpg
q 给进程组发送信号。killpg(pgrp, sig)等价于kill(-pgrp, sig);
q sigqueue
q 给进程发送信号,支持排队,可以附带信息。
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
if (signal(SIGUSR1, handler) ==SIG_ERR)
ERR_EXIT("signalerror");
pid_t pid = fork();
if (pid == -1)
ERR_EXIT("forkerror");
if (pid == 0)
{
kill(getppid(), SIGUSR1);
exit(EXIT_SUCCESS);
}
int n = 5;
do
{
n = sleep(n);
} while (n > 0);
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
}
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
if (signal(SIGUSR1, handler) ==SIG_ERR)
ERR_EXIT("signalerror");
pid_t pid = fork();
if (pid == -1)
ERR_EXIT("forkerror");
if (pid == 0)
{
/*pid = getpgrp();
kill(-pid,SIGUSR1);*/
killpg(getpgrp(),SIGUSR1);
exit(EXIT_SUCCESS);
}
int n = 5;
do
{
n = sleep(n);
} while (n > 0);
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
}
三、pause
q 将进程置为可中断睡眠状态。然后它调用schedule(),使linux进程调度器找到另一个进程来运行。
q pause使调用者进程挂起,直到一个信号被捕获
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
if (signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signalerror");
for (;;)
{
pause();
printf("pausereturn\n");
}
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
sleep(1);
}
信号(三)
一、alarm函数
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
if (signal(SIGALRM, handler) ==SIG_ERR)
ERR_EXIT("signal error");
alarm(1);
for (;;)
pause();
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
alarm(1);
}
二、可重入函数
q 为了增强程序的稳定性,在信号处理函数中应使用可重入函数。
q 所谓可重入函数是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错。因为进程在收到信号后,就将跳转到信号处理函数去接着执行。如果信号处理函数中使用了不可重入函数,那么信号处理函数可能会修改原来进程中不应该被修改的数据,这样进程从信号处理函数中返回接着执行时,可能会出现不可预料的后果。不可再入函数在信号处理函数中被视为不安全函数。
q 满足下列条件的函数多数是不可再入的:(1)使用静态的数据结构,如getlogin(),gmtime(),getgrgid(),getgrnam(),getpwuid()以及getpwnam()等等;(2)函数实现时,调用了malloc()或者free()函数;(3)实现时使用了标准I/O函数的
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
typedefstruct
{
int a;
int b;
} TEST;
TESTg_data;
voidhandler(int sig);
intmain(int argc, char *argv[])
{
TEST zeros = {0, 0};
TEST ones = {1, 1};
if (signal(SIGALRM, handler) ==SIG_ERR)
ERR_EXIT("signalerror");
g_data = zeros;
alarm(1);
for (;;)
{
g_data = zeros;
g_data = ones;
}
return 0;
}
voidunsafe_fun()
{
printf("%d %d\n", g_data.a,g_data.b);
}
voidhandler(int sig)
{
unsafe_fun();
alarm(1);
}
信号(四)
一、信号在内核中的表示
二、信号集操作函数
q #include<signal.h>
q intsigemptyset(sigset_t *set);
q intsigfillset(sigset_t *set);
q intsigaddset(sigset_t *set, int signo);
q intsigdelset(sigset_t *set, int signo);
q intsigismember(const sigset_t *set, int signo);
三.sigprocmask函数
q #include<signal.h>
q intsigprocmask(int how, const sigset_t *set, sigset_t *oset);
q 功能:读取或更改进程的信号屏蔽字。
q 返回值:若成功则为0,若出错则为-1
q 如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
void handler(int sig);
void printsigset(sigset_t *set)
{
int i;
for(i=1; i<NSIG; ++i)
{
if(sigismember(set, i))
putchar('1');
else
putchar('0');
}
printf("\n");
}
int main(int argc, char *argv[])
{
sigset_tpset;
sigset_tbset;
sigemptyset(&bset);
sigaddset(&bset,SIGINT);
if(signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signalerror");
if(signal(SIGQUIT, handler) == SIG_ERR)
ERR_EXIT("signalerror");
sigprocmask(SIG_BLOCK,&bset, NULL);
for(;;)
{
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return0;
}
void handler(int sig)
{
if (sig== SIGINT)
printf("recva sig=%d\n", sig);
else if(sig == SIGQUIT)
{
sigset_tuset;
sigemptyset(&uset);
sigaddset(&uset,SIGINT);
sigprocmask(SIG_UNBLOCK,&uset, NULL);
}
}
信号(五)
一、sigaction
q 包含头文件<signal.h>
q 功能:sigaction函数用于改变进程接收到特定信号后的行为。
q 原型:
int sigaction(int signum,const struct sigaction*act,const struct sigaction *old);
q 参数
q 该函数的第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)
q 第二个参数是指向结构sigaction的一个实例的指针,在结构 sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理
q 第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。
q 返回值:函数成功返回0,失败返回-1
q 第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
structsigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *,void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
__sighandler_tmy_signal(int sig, __sighandler_t handler);
intmain(int argc, char *argv[])
{
/*
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL)< 0)
ERR_EXIT("sigactionerror\n");
*/
my_signal(SIGINT, handler);
for (;;)
pause();
return 0;
}
__sighandler_tmy_signal(int sig, __sighandler_t handler)
{
struct sigaction act;
struct sigaction oldact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(sig, &act,&oldact) < 0)
return SIG_ERR;
return oldact.sa_handler;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
}
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT);
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL)< 0)
ERR_EXIT("sigactionerror");
for (;;)
pause();
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
sleep(5);
}
信号(六)
//01sigaction.c
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig);
intmain(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigset_ts;
sigemptyset(&s);
sigaddset(&s,SIGINT);
sigprocmask(SIG_BLOCK,&s, NULL);
if (sigaction(SIGINT, &act, NULL)< 0)
ERR_EXIT("sigactionerror");
for (;;)
pause();
return 0;
}
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
sleep(5);
}
//02sigaction_rev.c
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int, siginfo_t *, void *);
intmain(int argc, char *argv[])
{
struct sigaction act;
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGINT, &act, NULL)< 0)
ERR_EXIT("sigactionerror");
for (;;)
pause();
return 0;
}
voidhandler(int sig, siginfo_t *info, void *ctx)
{
printf("recv a sig=%d data=%ddata=%d\n", sig, info->si_value.sival_int, info->si_int);
}
//03sigqueue
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
intmain(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage%s pid\n", argv[0]);
exit(EXIT_FAILURE);
}
pid_t pid = atoi(argv[1]);
union sigval v;
v.sival_int = 100;
sigqueue(pid, SIGINT, v);
return 0;
}
一、sigqueue函数
q 功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
q 原型:
int sigqueue(pid_t pid, int sig, constunion sigval value);
q 参数
q sigqueue的第一个参数是指定接收信号的进程id,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。
q 返回值成功返回0,失败返回-1
q sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。
typedef union sigval
{
intsival_int;
void*sival_ptr;
}sigval_t;
//04sigaciton_rev.c
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int);
intmain(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGINT);
sigaddset(&s, SIGRTMIN);
sigprocmask(SIG_BLOCK, &s, NULL);
if (sigaction(SIGINT, &act, NULL)< 0)
ERR_EXIT("sigactionerror");
if (sigaction(SIGRTMIN, &act, NULL)< 0)
ERR_EXIT("sigactionerror");
if (sigaction(SIGUSR1, &act, NULL)< 0)
ERR_EXIT("sigactionerror");
for (;;)
pause();
return 0;
}
voidhandler(int sig)
{
if (sig == SIGINT || sig == SIGRTMIN)
printf("recv asig=%d\n", sig);
else if (sig == SIGUSR1)
{
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGINT);
sigaddset(&s, SIGRTMIN);
sigprocmask(SIG_UNBLOCK,&s, NULL);
}
}
//05sigqueue_send.c
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
intmain(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage%s pid\n", argv[0]);
exit(EXIT_FAILURE);
}
pid_t pid = atoi(argv[1]);
union sigval v;
v.sival_int = 100;
sigqueue(pid, SIGINT, v);
sigqueue(pid, SIGINT, v);
sigqueue(pid, SIGINT, v);
sigqueue(pid, SIGRTMIN, v);
sigqueue(pid, SIGRTMIN, v);
sigqueue(pid, SIGRTMIN, v);
sleep(3);
kill(pid, SIGUSR1);
return 0;
}
信号(七)
一、三种不同精度的睡眠
q unsignedint sleep(unsigned int seconds);
q intusleep(useconds_t usec);
q intnanosleep(const struct timespec *req, struct timespec *rem);
二、setitimer
q 包含头文件<sys/time.h>
q 功能setitimer()比alarm功能强大,支持3种类型的定时器
q 原型:
intsetitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
q 参数
q 第一个参数which指定定时器类型
q 第二个参数是结构itimerval的一个实例,结构itimerval形式
q 第三个参数可不做处理。
q 返回值:成功返回0失败返回-1
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#include<sys/time.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
voidhandler(int sig)
{
printf("recv a sig=%d\n",sig);
}
intmain(int argc, char *argv[])
{
if (signal(SIGALRM, handler) ==SIG_ERR)
ERR_EXIT("signalerror");
struct timeval tv_interval = {1, 0};
struct timeval tv_value = {5, 0};
struct itimerval it;
it.it_interval = tv_interval;
it.it_value = tv_value;
setitimer(ITIMER_REAL, &it, NULL);
for (;;)
pause();
return 0;
}
q ITIMER_REAL:经过指定的时间后,内核将发送SIGALRM信号给本进程
q ITIMER_VIRTUAL:程序在用户空间执行指定的时间后,内核将发送SIGVTALRM信号给本进程
q ITIMER_PROF:进程在内核空间中执行时,时间计数会减少,通常与ITIMER_VIRTUAL共用,代表进程在用户空间与内核空间中运行指定时间后,内核将发送SIGPROF信号给本进程。
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#include<sys/time.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
intmain(int argc, char *argv[])
{
struct timeval tv_interval = {1, 0};
struct timeval tv_value = {1, 0};
struct itimerval it;
it.it_interval = tv_interval;
it.it_value = tv_value;
setitimer(ITIMER_REAL, &it, NULL);
int i;
for (i=0; i<10000; i++);
;
struct itimerval oit;
setitimer(ITIMER_REAL, &it,&oit);
printf("%d %d %d %d\n",(int)oit.it_interval.tv_sec, (int)oit.it_interval.tv_usec,(int)oit.it_value.tv_sec, (int)oit.it_value.tv_usec);
return 0;
}
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<signal.h>
#include<sys/time.h>
#defineERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
intmain(int argc, char *argv[])
{
struct timeval tv_interval = {1, 0};
struct timeval tv_value = {1, 0};
struct itimerval it;
it.it_interval = tv_interval;
it.it_value = tv_value;
setitimer(ITIMER_REAL, &it, NULL);
int i;
for (i=0; i<10000; i++);
;
getitimer(ITIMER_REAL, &it);
printf("%d %d %d %d\n",(int)it.it_interval.tv_sec, (int)it.it_interval.tv_usec,(int)it.it_value.tv_sec, (int)it.it_value.tv_usec);
return 0;
}