赞
踩
信号是初步异步,线程是强烈异步
两者机制很少混合使用,仅仅会将少量的信号混入
顺序执行,可预知
哪个事件什么时候到来不确定,产生什么样的结果也不确定
异步事件的处理:
查询法:适合事件发生频率比较高
通知法:适合事件发生频率比较稀疏
信号是软件层面的中断
信号的响应依赖与中断机制
多半的信号的作用都是终止,或者终止+core
标准C里面的信号基本是摆设
core文件就是出错现场,利于找出程序错误
NAME
signal - ANSI C signal handling
SYNOPSIS
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
原型:void (*signal(int signum, void (*func)(int)))(int);
信号会打断阻塞的系统调用。
这就是说,在以前的程序中,有一行代码,用来忽视所有信号
只保留有用的信号的原因,就是为了防止自己的程序被信号打断。
标准信号一定会丢失,实时信号是不丢失的。
信号不可靠是指信号的行为不可靠。
很有可能第一次信号调用还没有结束的时候就发生了第二次调用
解决信号不可靠的问题。
一种特殊的函数:第一次调用还没有结束的情况下,第二次调用也不会出错。
所有的系统调用都是可重入的,一部分库函数也是可重入的,比如说memcpy,memmove
特别是关于指针的函数,要特别注意
拿rand函数(随机函数)举例,rand生成的数是伪随机数,当前的随机数是在上一个随机数的基础上生成的,
如果第一个随机数还没有生成,rand就被调用第二次,就会出现结果错误。
在函数名字中(linux中),有_r版本的,这个版本的就是可重入函数,就是可以用在信号处理函数里面的。
信号从收到到响应,有一个不可避免的延迟。 思考:如何忽略掉一个信号? 标准信号为什么要丢失? 一个信号的响应过程: 不是说程序随时有信号,随时可以检测到,而是只有在从内核态过渡到用户态的时候, 执行mask&pending之后才知道自己有没有信号,所以,程序接收到信号之后,仍然继续执行, 等程序进入内核态(比如说时间片到,程序和程序的信息被挂在内存),然后再到该程序执行的时候, 程序会将自己的mask和pending进行与运算,如果有哪一位变化,就知道有信号,就会把下一个要执行的地址 替换为信号响应函数的地址,去执行信号响应函数,之后再回到内核态,再设置mask和pending位, 再进入用户态,再进行与运算,发现信号已经处理完毕,正常执行后面的语句。 标准信号的响应,没有严格的顺序。 一般是先响应情节比较严重的信号,比如说段错误优先程序终止 而这个mask代表某一个信号怎么执行,或者怎么响应,pending代表信号是否到来,都是位图。 不能阻止信号到来,只能决定信号是否响应。 位图结构不管来多少个信号,都只有一个1,因为位图不累计。 那么对于标准信号,同时来一万个信号,也是只有一个1,所以只会响应一次。 但是对于实时信号,不会有信号丢失。 不能从信号处理函数中随意的往外跳,setjmp(),longjmp() 因为它们会错过一个把mask操作改回去的重要操作,导致以后永远错过某一个信号 所以setjmp(),longjmp()绝对不能在信号函数里面使用。
虽然在linux里面,用kill杀死进程,但它不是杀死,它是发信号,是因为大多数信号都是终止。
NAME
kill - send signal to a process
SYNOPSIS
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
NAME
raise - send a signal to the caller
SYNOPSIS
#include <signal.h>
int raise(int sig);
用信号计时,10ms以内的不准确(理论上)
NAME
alarm - set an alarm clock for delivery of a signal
SYNOPSIS
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
alarm没办法实现多任务的计时,只能有一个alarm
当有多个alarm定时的时候,只有最后一个alarm生效
例子:使用单一计时器,构造一组函数,实现任意数量的计时器
setitimer更精确,不想alarm只能到秒,而且它有多种时钟模式
任意数量的计时器封装成库:anytime
NAME
getitimer, setitimer - get or set value of an interval timer
SYNOPSIS
#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value)
NAME
pause - wait for signal
SYNOPSIS
#include <unistd.h>
int pause(void);
有一些环境中,sleep是使用alarm和pause来封装的,因为alarm存在bug,所以sleep一定存在bug
所以在真正发布的程序中,不可能有sleep存在。
但是有的环境中,sleep是使用nanosleep封装的,所以在当前环境没事。
所以在需要移植的程序中,不要用sleep
流控算法:信号令牌桶封装成库-mytbf
NAME
abort - cause abnormal process termination
SYNOPSIS
#include <stdlib.h>
void abort(void);
人为的制造一个异常
NAME
system - execute a shell command
SYNOPSIS
#include <stdlib.h>
int system(const char *command)
调用shell,来完成一条shell命令
可以简单的看成是few的封装
因为有的环境sleep是使用alarm+pause封装的,
而alarm多余一个的时候是会出错的,所以我们不用sleep
7.1 nanosleep();
7.2 usleep();
7.3 select();这个函数的副作用可以用来休眠,而且是安全可靠的
NAME sigemptyset, sigfillset, sigaddset, sigdelset, sigismember - POSIX signal set oper‐ ations 信号集合类型:sigset_t SYNOPSIS #include <signal.h> 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);// 判断信号是否存在信号集合当中
mask屏蔽字:位图全为1 pending:位图全为0 当一个进程从内核态返回用户态的时候,会进行mask&pending mask集合的操作: sigprocmask(); // 控制mask,可以决定信号是否被响应 NAME sigprocmask, rt_sigprocmask - examine and change blocked signals SYNOPSIS #include <signal.h> /* Prototype for the glibc wrapper function */ // 把set信号集的所有信号全部设置为how int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); /* Prototype for the underlying system call */ int rt_sigprocmask(int how, const kernel_sigset_t *set, kernel_sigset_t *oldset, size_t sigsetsize); /* Prototype for the legacy system call (deprecated) */ int sigprocmask(int how, const old_kernel_sigset_t *set, old_kernel_sigset_t *oldset); pending集的操作: 这是一个系统调用,所以一定会进入内核 它的作用是进入内核,去取出pending的状态 但是取出来的信号是已经响应完的信号,因为pending在出内核态的时候, 进行完与mask的与操作,就自动去执行存在的信号,然后重置mask和pending, 所以,这个时候你带回来的pending位图是旧的位图,是信号响应之前的位图 所以,这个函数的价值不高,没有什么用,用maks操作函数就够了 sigpending(); NAME sigpending, rt_sigpending - examine pending signals SYNOPSIS #include <signal.h> int sigpending(sigset_t *set);
sigsuspend(); // 可以做信号驱动程序 NAME sigsuspend, rt_sigsuspend - wait for a signal SYNOPSIS #include <signal.h> int sigsuspend(const sigset_t *mask); 功能和pause很类似都是等待一个信号 但是pause和其他信号函数共同做成的信号驱动程序不是原子的。 所以pause不能用来作信号驱动程序,用锁可以 sigaction(); 代替 signal() 这个函数 NAME sigaction, rt_sigaction - examine and change a signal action SYNOPSIS #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) 有了setitimer和sigaction之后,程序中就不要再用alarm和signal
实时信号不会丢失,ulimit可以查看信号队列的最大个数,可以修改
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。