- 信号是软件中断。信号提供了一种处理异步事件的方法。
- 不存在编号为0的信号(因为有特殊作用)
-产生信号的方式有很多:终端键、硬件异常(除数为0、无效的内存引用等)、 kill函数、软件条件发生、关某种进程等 - 信号处理:
- 忽略此信号(SIGKILL和SIGSTOP不可忽略)、捕捉信号、执行系统默 认动作(大多数是终止进程)
- 在系统默认动作列,”终止+core”表示在进程当前工作目录的core文件中复制了该进程的内存映像。大多数UNIX系统使用core文件来检查进程终止时的状态。
- 不产生core文件的条件:
a.进程是设置用户ID的,而且当前用户非程序文件的所有者
b.进程是设置组ID的,而且当前用户并非该程序文件的组所有者
c.用户没有写当前工作目录的权限
d.文件已存在,而且用户对该文件设有写权限
e.文件太大
- kill -l(linux指令,则可获取全部命令)
- 不可靠信号
- 信号处理函数执行完毕,信号恢复成默认处理方式(Linux已经改进)
- 会出现信号丢失,信号不排队
- 1-31 都是不可靠的,会出现信号丢失现象
- 会出现同一信号多次发生只接收到一次的情况
- 可靠信号
- 34-64不可靠信号
- 不会出现信号丢失,支持排队,信号处理函数执行完毕,不会恢复成缺省处理方式
- 实时信号 : 就是可靠信号
- 非实时信号:不可靠信号
- SIGINT(Ctrl+C)
- 注:每个信号的解析(请看其它文档)
- void (*signal(int sig,void(*func)(int)))(int)
- 参数:
sig:要捕捉的信号
func: SIG_IGN 捕捉动作为:内核表示忽略此信号(预定义宏)
SIG_DFL 捕捉动作为:执行该信号的系统默认动作
捕捉函数:执行由func指向的信号响应函数
返回值: 成功:最近一次调用该函数时第二个参数的值
失败:SIG_ERR
- 当执行一个程序时,接收信号的状态都是系统默认或忽略(根据信号来决定)
- 注意:
1. execl执行的进程,信号不会再捕捉了(具体看execl函数)
2. fork后的子进程会继承父进程的信号处理方式 - int sigaction(int signo,const struct sigaction* restrict act,
struct sigaction* restrict oact)
参数:
signo:信号值
act: 非空 修改其动作
oact:非空 返回该信号的上一个动作
struct sigaction {
void (*sa_handler)(int); //标准响应函数(不是常量SIG_IGN(信号忽略)和SIG_DFL(默认信号处理))
void (*sa_sigaction)(int, siginfo_t *, void *); //备用响应函数,这两个函数一般 只会响应一个
sigset_t sa_mask;//阻塞的信号集,信号捕捉成功恢复原先值
int sa_flags;//功能选择标记(见图10-16)
};
void handler(int signo,siginfo_t* info,void* context);
struct siginfo{
int si_signo; //信号数字
int si_errno; //错误编码
int si_code; //备注(取决于信号,见图10-17)
pid_t si_pid; //发送信号的进程的id
uid_t si_uid;//发送信号的用户id
void *si_addr;//造成故障的地址
int si_status;//信号退出值
union sigval si_value;//信号传递的值
}
union sigval {
int sival_int;//整数值
void* sival_ptr;//指针值
}
返回值: 成功 0;出错 -1
-signal 例子:
#include可重入函数#include #include #include #include #include void sig_int(int signo) { printf("signal num = %dn",signo); } int main(int argc,char** argv) { if(signal(SIGINT,sig_int) == SIG_ERR) perror("signal(SIGINT) errorn"); raise(SIGINT); return 0; }
- 可重入函数是可以随时被中断,并不会影响程序运行的(异步信号安全的),信号处理操作期间,它会阻塞任何会引起不一致的信号发送
- 大多数函数是不可重入的(信号处理中断函数会造成程序问题的):
a. 已知它们使用静态数据结构
b. 它们调用malloc或free
c. 它们是标准I/O函数 - 可重入函数(见百度)
- Int kill(pid_t pid,int sig) 给对应进程发送信号
- 注意:要有权限才可以发送相对应的进程(一般同一个用户启动就可以)
pid: >0 发送给进程号为pid的进程 <-1 发送给组ID等于-pid的进程组里面的所有进程 0 信号发送给当前进程同一个进程组内的所有进程 -1 信号被发送给所有进程(如果当前进程对其有权限) sig: 发送的信号值 返回值: 成功:0 失败:-1
- int raise(int signo) 给自身发送信号
- unsigned int alarm(unsigned int seconds) 定时器信号啊函数
- int sigqueue(pid_t pid,int signo,const union sigval value) 发送信号可附带数据(value共用体同sigaction参数中的共用体)
- pause(void) 进程或线程休眠(遇到信号则退出休眠状态)
#include信号集#include #include #include #include void sig_int(int signo,siginfo_t* info,void* context) { printf("信号值:%d--->信号传递的值:%sn",signo,(char*)info->si_value.sival_ptr); } int main() { struct sigaction act,oact; union sigval value; act.sa_handler = sig_int; act.sa_flags = SA_SIGINFO;//设置为传递信息 if(sigaction(SIGUSR1,&act,&oact) == -1)//等待信号处理 perror("sigaction(SIGINT)n"); value.sival_ptr = "hello world"; if(sigqueue(getpid(),SIGUSR1,value) == -1) perror("sigqueue errorn"); return 0; }
- int sigemptyset(sigset_t* set);//清空信号集合
- int sigfillset(sigset_t* set);//初始化信号集合,使其包括所有信号
- int sigaddset(sigset_t* set,int signo);//增加信号到信号集
- int sigdelset(sigset_t* set,int signo);//从信号集删除一个信号
- int sigismember(const sigset_t* set,int signo); //测试一个指定的位是否被信号集包含(返回值: 1为真,0为假)
可以检测或更改,或同时进行检测和更改进程的信号屏蔽字(屏蔽字:规定了当前阻塞而不能递送给该进程的信号集),SIGKILL和SIGTOP不能被阻塞
- int sigprocmask(int how,const sigset_t* restrict set,sigset_t* restrict oset);
参数: oset: 非空指针, 那么进程的当前信号屏蔽字通过oset返回(如果设置了屏蔽字,则在此时还是进程当前的屏蔽字) 空指针, 不返回当前信号屏蔽字的内容 set: 非空指针, 则参数how指针如何修改当前信号屏蔽字 空指针, 不改变该进程的信号屏蔽字,how的值也无意义 how: SIG_BLOCK 当前信号屏蔽字和set执行信号集的并集 SIG_UNBLOCK 当前信号屏蔽字和set所指向信号集补集的交集(解除set信号集阻塞) SIG_SETMASK set所指向的值 sigprocmask函数调用后如果有任何未决的、不再阻塞的信号,则在sigprocmask返回前,至少将其中之一递送给该进程
例子:
#include#include #include #include #include #include int main() { sigset_t newmask,oldmask; sigemptyset(&newmask); sigfillset(&newmask); if(sigismember(&newmask,SIGINT)) printf("SIGINT existn"); if(sigismember(&newmask,SIGUSR1)) //因为sigfillset,所以有这个信号 printf("SIGUSR1 existn"); sigaddset(&newmask,SIGINT);//因为已经有了这个信号,所以无效 sigdelset(&newmask,SIGINT); if(sigismember(&newmask,SIGINT) == 0) printf("not SIGINTn"); if(sigprocmask(SIG_SETMASK,&newmask,&oldmask) < 0) perror("sigprocmask(SIG_BLOCK,NULL,&oldmask) errorn"); if(sigismember(&oldmask,SIGUSR1) == 0) //因为是进程之前的信号集,所以没有这个信号 printf("not SIGINTn"); return 0; }
#未完待续…



