并发(信号 线程)
同步
异步
异步事件的处理:查询法,通知法
一、信号
1、信号的概念
信号是软件中断
2、signal();
ANSI C 信号处理:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
当signum信号到来执行handler。
返回值:成功,返回以前的信号处理配置;出错,返回SIG_ERR。
注意:没有被忽略的信号(某些信号的默认行为就是忽略)会唤醒正在睡眠的进程;
如果信号被捕捉则唤醒后先执行信号处理函数,然后继续执行,否则进程直接结束.
信号会打断阻塞的系统调用。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void int_handler(int s)
{
write(1,"!",1);
}
int main()
{
int i;
// signal(SIGINT,SIG_IGN);//SIGINT中断一个信号,SIG_IGN忽略一个信号。
signal(SIGINT,int_handler);
for(i = 0 ; i < 10; i++)
{
write(1,"*",1);
sleep(1);
}
exit(0);
}
3、信号的不可靠
标准信号会丢失,实时信号不会丢失。
信号的行为不可靠。
信号到来时内核为其布置现场,信号在处理这个行为的同时,又来了一个新的相同的信号,
内核有可能会将执行现场布置在同一个位置,旧的执行现场将会被新的信号的执行现场所覆盖。
方法:构造一个链实结构。
4、可重入函数
第一次调用还没结束第二次调用又来了,但不会出错。
所有的系统调用都是可重入的,一部分库函数也是可重入的,比如:memcpy。
不可重入:rand产生随机值,但是rand_r就是可重入的。
5、信号的响应过程
内核至少为每个进程维护来两个位图mask&pending
信号从收到到响应有一个不可避免的延迟
思考:
1>如何忽略掉一个信号的?
将mask位一直置0
2>标准信号为什么要丢失。
mask置零时来多个信号但却不会执行,所以会丢失。
3>标准信号的响应没有严格的顺序。
4>不能从信号处理函数中随意的往外跳。(sigsetjmp, siglongjmp)
6、常用函数
1>向进程发送信号:int kill(pid_t pid, int sig);
返回值:成功返回0,失败返回-1并设置errno。
pid > 0 发送给进程 ID 是 pid 的进程
pid = 0 发送给与调用进程的同组进程
pid = -1 发送给有权限发送所有进程
pid < -1 发送给进程组|pid|的进程
注意:超级用户进程拥有向任何进程发送信号的权限,普通进程只能发送给与发送者 UID或者 EUID 相同的进程。
2>向自己发送信号,准确的说是发送给调用线程:int raise(int sig);
返回值:成功0,失败非0.
注意:这个函数发送的信号如果被捕捉,则先执行完信号处理函数 raise 才返回
2.1>获取或设置一个间隔计时器的值:
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
which代表设置那个时钟 ITIMER_REAL、ITIMER_VIRTUAL、ITIMER_PROF
第二个参数代表新的时钟周期。
struct itimerval {
struct timeval it_interval; /* Interval for periodic timer */
struct timeval it_value; /* Time until next expiration */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
返回值:成功0,出错-1,并设置errno。
例:使用单一计时器,利用alarm或setitimer构造一组函数,实现任意数量的计时器。
//漏桶 srtitimer替换alarm
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#define CPS 10
#define BUFSIZE CPS
static volatile int loop = 1;
void alrm_handler(int s)
{
// alarm(1);
loop = 0;
}
int main(int argc,char **argv)
{
int sfd,dfd = 1;
char buf[BUFSIZE];
int len,ret,pos;
struct itimerval itv;
if(argc < 2)
{
fprintf(stderr,"Usage:%s <srcfile>\n",argv[0]);
exit(1);
}
signal(SIGALRM,alrm_handler);
// alarm(1);
itv.it_interval.tv_sec = 1;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 1;
itv.it_value.tv_usec = 0;
if(setitimer(ITIMER_REAL,&itv,NULL) < 0)
{
perror("setitimer()");
exit(1);
}
do
{
sfd = open(argv[1],O_RDONLY);
if(sfd < 0)
{
if(errno != EINTR)
{
perror("open()");
exit(1);
}
}
}while(sfd < 0);
while(1)
{
while(loop)
pause();//避免盲等
loop = 1;
while((len = read(sfd,buf,BUFSIZE)) < 0)
{
if(errno == EINTR)
continue;
perror("read()");
break;
}
if(len == 0)
break;
// len > 0