Linux中的信号
kill -9 pid #kill只是起到发送信号的作用,-9参数才是杀死进程
ctrl+c相当于kill 2 pid
3和9不可被捕捉替换
信号可做两个进程之间的通讯,同步,而不是发送数据
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
/*
#define SIGLOST 29
*/
#define SIGPWR 30
#define SIGSYS 31
/* signal 31 is no longer "unused", but the SIGUNUSED macro remains for backwards compatibility */
#define SIGUNUSED 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX _NSIG
//捕获signum信号,重新定义这个信号的操作函数为myfunc()
signal(int signum,myfunc());
signal(SIGINT,myfunc);
signal(SIGINT,SIG_IGN);//参数SIG_IGN表示忽略这个信号,但quite和kill信号无法屏蔽
如何发起异步操作
kill 命令 eg:kill -signum pid
int kill(pid,signum);
pid>0 发给pid进程
pid=0 发给当前进程组的所有进程(fork出来的进程)
pid=-1 发送给所有进程
pid<0 发送给|PID|所对应的组上
pid=getpid()
gpid=getgpid()
raise
自举信号,会给自己发送一个信号
int raise(int sig);
int kill(getpid(),signum);
alarm
定时函数
unsigned int alarm(unsigned int seconds);
函数会在所指定的seconds之后收到SIGALRM信号
signal(SIGALRM,printf);
alarm(2);
第二次设置alarm时,会立即返回上次未消耗地时间
ualarm
useconds_t ualarm(useconds_t usecs, useconds_t interval);
以useconds为单位,第一个参数为第一次产生时间,第二个参数为间隔产生
setitimer 定时器
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
Linux会给进程提供三个定时器
ITIMER_REAL:以逝去时间递减
ITIMER_VIRTUAL:
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
信号可能会打断阻塞函数,可以用来做超时响应
因为信号可能打断accept阻塞,所以还要判断一次错误类型,如果是打断,则重新accept
获取文件大小方法
sigaction对象
在早期,signal(int signum,myfunc());没有设计得比较周全,只能给绑定的函数传入一个信号类型的参数,所以后期才有了sigaction对象
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
struct sigaction
{ //两个函数指针只调用其一,通过sa_flags设置
void (*sa_handler)(int);//若调用此,和普通signal函数没区别
//信号类型,发射信号时当前进程系统信息结构体(如下),给sa_handler传的参数,通过sigqueue方法发送
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;//信号屏蔽集
int sa_flags; //会影响信号接受特殊标志,可设置为0(只调用sa_handler)和SA_SIGINFO(调用sa_sigaction)
void (*sa_restorer)(void);
};
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
}
- 信号会唤醒当前进程的阻塞状态
sigqueue
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<string.h>
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("arguments error!");
exit(0);
}
pid_t pid=atoi(argv[1]);//将进程号转化为整数
union sigval v;
v.sival_int=100;
//这儿只是利用SIGINT来发送数据,
//任何信号都行,只需要发送端与接收端规定一致即可
sigqueue(pid,SIGINT,v);//给一pid发送信号和void *参数
return 0;
}
sigval_t
union sigval {
int sival_int;
void *sival_ptr;
};
信号集合
信号集是为了方便批量设置屏蔽(不接收)各种信号,SIG_IGN是忽略(接收不处理)
用位图的形式(如一个int有32位)存储信号
- sigset_t sa_mas
int sigemptyset(sigset_t *set);//清空
int sigfillset(sigset_t *set);//填充
int sigaddset(sigset_t *set, int signum);//给信号集添加信号
int sigdelset(sigset_t *set, int signum);//删除
int sigismember(const sigset_t *set, int signum);//查找
设置信号屏蔽集合
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);//第三个参数用来做上一集合备份
第一个参数为一下几种
SIG_BLOCK//阻塞
SIG_UNBLOCK//非阻塞
SIG_SETMASK//屏蔽
未决信号
sigpending(sigset)用来获取已接收的被屏蔽信号,若此信号解除屏蔽,会立即执行一次此信号的回调函数
int block
32bit
00000000000000000000000000000100
sigsuspend 函数 等待信号
阻塞接收所设置的信号,若接收了其他信号,则解除阻塞往下运行
int sigsuspend(const sigset_t *mask);
运用signal IO做socket触发
要用fcntl给skcket绑定个PID,因为signal需要通过PID发送
设置dev时尽量不要用 fcntl设置,用ioctl
参考
https://blog.csdn.net/freeking101/article/details/78338497