《Unix/Linux编程实践教程》chapter7 事件驱动编程

chapter7 事件驱动编程

章节知识总结

curses库是一组函数,程序员可以用它们来设置光标的位置和终端屏幕上显示的字符样式。一个小的demo如下:

#include<stdio.h>
#include<curses.h>

//在终端显示"Hello world"
int main(){
    initscr();
    clear();
    move(10,20);
    addstr("Hello world");
    move(LINES-1,0);
    refresh();
    getch();
    endwin();
}

sleep调用可以通过alarmpause两个操作实现:

int main(){
    void wakeup(int);
    //模拟sleep(4)
    signal(SIGALRM,wakeup);     //为SIGALRM设置一个处理函数
    alarm(4);                   //调用alarm
    pause();                    //调用pause
    printf("Morning so sonn?\n");
}

进程可以使用3种方式来计时:

在这里插入图片描述

  1. ITIMER_REAL:计量真实事件
  2. ITIMER_VIRTUAL:只有进程在用户态时才计时
  3. ITIMER_PROF:这个计时器在进程运行于用户态或由该进程调用而陷入核心态时计时。当这个计时器用尽,发送SIGPROF消息。

Unix提供了间隔计时器这种更精确的计时器,可以通过setitimergetitimer来搭配使用间隔计时器。

一个计时器是内核的一种机制。通过这种机制,内核在一定的时间之后向进程发送SIGALRM.alarm系统调用用在特定的实际秒数之后发送SIGALRM给进程。setitimer系统调用以更高的精度控制计时器,同时能够以固定的时间间隔发送信号。

在第六章中我们知道,一个进程调用signal在以下3种处理信号的方法之中选择:

  1. 默认操作(一般是终止进程),比如signal(SIGALRM,SIG_DFL)
  2. 忽略信号,比如signal(SIGALRM,SIG_IGN)
  3. 调用一个函数,比如signal(SIGALRM,handler)

signal提供了一种简单但是不完整的信号处理机制。POSIX接口,即sigaction提供了复杂的、明确定义的方法来控制进程如何对各种信号组合做出反应。

一段修改一个数据结构的代码如果在运行时被打断将导致数据的不完整或损毁,则称这段代码为临界区

在Unix,我们可以使用sigprocmask将一些信号处理,其函数原型为int res=sigprocmask(int how,const sigset_t* sigs,sigset_t* prev),其中sigs指向使用的信号列表的指针.

以下函数用来添加或删除信号列表:

  • sigemptyset(sigset_t *setp):清除有setp指向的列表中的所有信号
  • sigfillset(sigset_t* setp):添加所有的信号到setp指向的列表
  • sigaddset(sigset_t* setp,int signum):添加signum到setp指向的列表
  • sigdelset(sigset_t* setp,int signum):从setp指向的列表中删除signum所标识的信号

一个小的阻塞用户信号demo:

sigset_t sigs,prevsigs;         //define two signal sets
sigempty(&sigs);
sigaddset(&sigs,SIGINT);
sigaddset(&sigs,SIGQUIT);
sigprocmask(SIG_BLOCK,&sigs,&prevsigs);
//...
sigprocmask(STG_SET,&prevsigs,NULL);        //restore previous mask

一个信号处理者或者一个函数,如果在激活状态下能被调用而不引起任何问题就称之为可重入的。

kill向一个进程发送一个信号。发送信号的进程的用户ID必须和目标进程的用户ID相同,或者发送信号的进程的拥有者是一个超级用户。一个进程可以向自己发送信号。

Unix有两个信号可以被用户程序使用,它们是SIGUSR1SIGUSR2,这两个信号没有预定义任务,可以使用它们以避免使用已经有预定义语义的信号。

Unix有两个异步输入系统,一种方法是当输入就绪时发送信号,另一个系统当输入被读入时发送信号。UCB中通过设置文件描述块的O_ASYNC尾来实现第一个方法,第二种方法是POSIX标准,它调用aio_read

其中UCB的主要处理流程如下:

void enable_kbd_signals(){
    int fd_flags;

    //告诉内核发送通知消息给进程
    fcntl(0,F_SETOWN,getpid());
    //取得文件描述符
    fd_flags=fcntl(0,F_GETFL);
    //设置O_ASYNC和写入
    fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
}
系统调用
alarm、setitimer 和 getitimer
alarm
用途设置发送信号(SSIGALRM)的计时器
头文件#include<unistd.h>
函数原型unsigned old=alarm(unsigned seconds)
参数seconds等待的时间(秒)
返回值-1:出错 ; old:计时器剩余时间
setitimer,getitimer
用途取得或设置间隔计时器
头文件#include<sys/time.h>
函数原型result=getitimer(int which,struct itimerval& val); result=setitimer(int which,const struct itimerval* newval, struct itimerval* oldval)
参数which: 获取或设置的计时器(三种); val:向当前设置值的指针 ; newval: 指向要被设置值的指针 ; oldval:指向被替换的设置值的指针
返回值-1:出错 ; 0: 成功
pause 和 kill
pause
用途挂起进程直到一个信号到达
头文件#include<unistd.h>
函数原型result=pause()
参数没有参数
返回值总是-1
kill
用途向一个进程发送一个信号
头文件#include<sys/types.h> #include<signal.h>
函数原型int kill(pid_t pid,int sig)
参数pid:目标进程id; sig:要被发送的信号
返回值-1:失败 ; 0:成功
sigaction 和 sigprocmask
sigaction
用途指定一个信号的处理函数
头文件#include<signal.h>
函数原型res=sigaction(int signum,const struct sigaction* action, struct sigaction* prevaction);
参数signum:要处理的信号; action:指针,指向描述操作的结构;prevaction:指针,指向描述被替换操作的结构
返回值-1:失败; 0:成功
sigprocmask
用途修改当前的信号挡板
头文件#include<signal.h>
函数原型int res=sigprocmask(int how,const sigset_t* sigs,sigset_t* prev);
参数how:如果修改信号挡板(SIG_BLOCK添加信号,SIG_UNBLOCK删除信号,SIG_SET替换信号); sigs:指向使用的信号列表的指针 ; prev: 指向之前的信号挡板列表的指针(或为null)
返回值-1:失败 ; 0:成功
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值