事件驱动编程——《Unix/Linux编程实践教程》读书笔记(第7章)

1、curses库

/* 基本curses函数 */
initscr();            // 初始化curses库和tty
endwin();             // 关闭curses并重置tty
refresh();            // 使屏幕按照你的意图显示
move(r, c);           // 移动光标到屏幕的(r, c)位置
addstr(s);            // 在当前位置画字符串s
addch(c);             // 在当前位置画字符c
clear();              // 清屏
standout();           // 启动standout模式(一般使屏幕反色)
standend();           // 关闭standout模式

2、

man 3 sleep
#include <unistd.h>
unsigned int sleep(unsigned int n);
/*
 * sleep() makes the calling thread sleep until n seconds
 * have elapsed or a signal arrives which is not ignored.
 *
 * Zero if the requested time has elapsed, or the number
 * of seconds left to sleep, if the call was interrupted
 * by a signal handler.
 */

sleep()的工作原理

系统中的每个进程都有一个私有的闹钟(alarm clock)。这个闹钟很像一个计时器,可以设置在一定秒数后闹铃。时间一到,时钟就发送一个信号SIGALRM到进程。除非进程为SIGALRM设置了处理函数(handler),否则信号将杀死这个进程。sleep函数由3个步骤组成:

/* sleep()的工作原理 */
signal(SIGALRM, handler);
alarm(num_seconds);
pause();

一下是对alarm()和pause()的描述。

man 2 alarm
#include <unistd.h>
unsigned int alarm(unsigned int n_seconds);
/*
 * alarm() arranges for a SIGALRM signal to be delivered to
 * calling process in n seconds.
 * If n_seconds is zero, any pending alarm is canceled.
 * In any envet any previously set alarm() is canceled.
 *
 * alarm() returns the number of seconds remaining until
 * any previously scheduled alarm was due to be delivered,
 * or zero if there was no previously scheduled alarm.
 */
man 2 pause
#include <unistd.h>
int pause(void);
/*
 * pause() causes the calling process (or thread) to sleep until
 * a signal is delivered that either terminates the process or
 * causes the invocation of a signal-catching function.
 *
 * pause() returns only when a signal was caught and the
 * signal-catching function returned. In this case pause()
 * returns -1, and errno is set to EINTR.
 */

精度更高的时延:

#include <unistd.h>
int usleep(useconds_t usec);

3、三种计时器:真实、进程和实用

(1)ITIMER_REAL:这个计时器计量真实时间。当这个计时器用尽,发送SIGALRM消息。

(2)ITIMER_VIRTUAL:虚拟计时器(virtual timer)只有进程在用户态运行时才计时。当虚拟计时器用尽,发送SIGVTALRM消息。

(3)ITIMER_PROF:这个计时器在进程运行于用户态或由该进程调用而陷入核心态时计时。当这个计时器用尽,发送SIGPROF消息。

4、set_ticker.c

/*
 * set_ticker.c
 * set_ticker(number_of_milliseconds)
 * arranges for interval timer to issue SIGALRMs at regular intervals
 * return 01 on error, 0 for ok
 * arg in milliseconds, converted into whole seconds and microseconds
 * note: set_ticker(0) turns off ticker
 */

#include <stdio.h>
#include <sys/time.h>

int set_ticker(int n_msecs)
{
    struct itimerval new_timeset;
    long n_sec, n_usecs;

    n_sec = n_msecs / 1000;
    n_usecs = (n_msecs % 1000) * 1000L;

    new_timeset.it_interval.tv_sec = n_sec;
    new_timeset.it_interval.tv_usec = n_usecs;

    new_timeset.it_value.tv_sec = n_sec;
    new_timeset.it_value.tv_usec = n_usecs;

    return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

结构体itimerval、timeval的描述:

struct itimerval
{
    struct timeval it_valuse;      /* time to next timer expiration */
    struct timeval it_interval;    /* reload it_value with this */
}

struct timeval
{
    time_t      tv_sec;        /* seconds */
    suseconds   tv_usec;       /* and microseconds */
}

函数getitimer、setitimer的描述:

man 2 getitimer
#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);

5、早期的信号处理机制

各种事件促使内核向进程发送信号。这些事件包括用户的击键、进程的非法操作和计时器到时。一个进程调用signal在以下3种处理信号的方法之中选择:

(1)默认操作(一般是终止进程),比如,signal(SIGALRM, SIG_DFL)

(2)忽略信号,比如,signal(SIGALRM, SIG_IGN)

(3)调用一个函数,比如,signal(SIGALRM, handler)

6、POSIX中替代signal()的函数sigaction()

(1)

man 2 sigaction
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
              struct sigaction *oldact);

/* 其中 */
struct sigaction {
    void (*sa_handler)(int);  /* SIG_DFL, SIG_IGN, or function */
    void (*sa_sigaction)(int, siginfo_t *, void *);  /* new handler */
    sigset_t sa_mask;  /* signals to block while handling */
    int sa_flags;  /* enable various behaviors */
    void (*sa_restorer)(void);/* POSIX does not specify this element */
};

(2)sa_flags是用一些位来控制处理函数如何应对上述4

sigaction()的概述比较麻烦,用一个例程来了解一下吧:

/*
 * sigactdemo.c
 * purpose: shows use of sigaction()
 * feature: blocks ^\ while handling ^C
 *          does not reset ^C handler, so two kill
 */

#include <stdio.h>
#include <signal.h>

#define INPUTLEN (100)

int main(void)
{
    struct sigaction    newhandler;         /* new settings */
    sigset_t            blocked;            /* set of blocked sigs */
    void                inthandler(int);
    char                x[INPUTLEN];

    /* load these two members first */
    newhandler.sa_handler = inthandler;     /* handler function */
    newhandler.sa_flags = SA_RESETHAND | SA_RESTART;
                                            /* options */

    /* then build the list of blocked signals */
    sigemptyset(&blocked);                  /* clear all bits */
    sigaddset(&blocked, SIGQUIT);           /* add SIGQUIT to list */
    newhandler.sa_mask = blocked;           /* store blockmask */

    if (sigaction(SIGINT, &newhandler, NULL) == -1)
        perror("sigaction");
    else
        while (1)
        {
            fgets(x, INPUTLEN, stdin);
            printf("input: %s\n", x);
        }
    return 0;
}

void inthandler(int s)
{
    printf("Called with signal %d\n", s);
    sleep(s);
    printf("done handling signal %d\n", s);
}

事件驱动编程——《Unix/Linux编程实践教程》读书笔记(第7章)

时间: 2024-12-23 14:47:15

事件驱动编程——《Unix/Linux编程实践教程》读书笔记(第7章)的相关文章

SQL Server2012 T-SQL基础教程--读书笔记(5-7章)

SQL Server2012 T-SQL基础教程--读书笔记(5-7章) SqlServer T-SQL 示例数据库:点我 Chapter 05 表表达式 5.1 派生表 5.1.1 分配列别名 5.1.2 使用参数 5.1.3 嵌套 5.1.4 多个引用 5.2 公用表表达式 5.2.1 分别列别名 5.2.2 使用参数 5.2.3 定义多个CTE 5.2.4 CTE的多次引用 5.2.5 递归CTE 5.3 视图 5.3.1 视图和ORDER BY 子句 5.3.2 视图选项 5.4 内嵌表

《Linux内核》课本读书笔记 第三章

进程和程序:编写shell——《Unix/Linux编程实践教程》读书笔记(第8章)

1.Unix shell的功能 shell是一个管理进程和运行程序的程序.所有常用的shell都有3个主要功能: (1)运行程序: (2)管理输入和输出 (3)可编程 shell同时也是带有变量和流程控制的编程语言. 2.Unix的进程模型 一个程序是存储在文件中的机器指令序列,一般它是由编译器将源代码编译成二进制格式的代码.运行一个程序意味着将这些机器指令序列载入内存然后让处理器(CPU)逐条执行.在Unix术语中,一个可执行程序是一些机器指令机器数据的序列.一个进程是程序运行时的内存空间和设

系统调用操作文件——《Unix/Linux编程实践教程》读书笔记

1.who命令通过读系统日志的内容显示当前已经登录的用户. 2.Unix系统把数据存放在文件中,可以通过以下系统调用操作文件: open(filename, how) creat(filename, mode) read(fd, buffer, amt) write(fd, buffer, amt) lseek(fd, distance, base) close(fd) 3.进程对文件的读/写都要通过文件描述符,文件描述符表示文件和进程之间的连接. 4.每次系统调用都会导致用户模式和内核模式的切

终端控制和和信号——《Unix/Linux编程实践教程》读书笔记(第6章)

1.有些程序处理从特定设备来的数据.这些与特定设备相关的程序必须控制与设备的连接.Unix系统中最常见的设备是终端. 2.终端驱动程序有很多设置.各个设置的特定值决定了终端驱动程序的模式.为用户编写的程序通常需要设置终端驱动程序为特定的模式. 3.键盘输入分为3类,终端驱动程序对这些输入做不同的处理.大多数建代表常规数据,它们从驱动程序传输到程序.有些键调用驱动程序中的编辑函数.如果按下删除键,驱动程序将前一个字符从它的行缓冲中删除,并将命令发送到终端屏幕,使之从显示器中删除字符.最后,有些键调

目录与文件属性——《Unix/Linux编程实践教程》读书笔记

1.ls产生一个文件名的列表,它大致是这样工作的: open directory +-> read entry - end of dir? -+ |__ display file info | close directory <--------------+ 2.目录是一种特殊的文件,它的内容是文件和目录的名字.与普通文件不同的是,目录文件永远不会空,每个目录至少包含2个特殊的项,即 "."和"..",其中 "."不是当前目录,&qu

I/O重定向和管道——《Unix/Linux编程实践教程》读书笔记(第10章)

1.I/O重定向的概念与原因 及 标准输入.输出的标准错误的定义 所以的Unix I/O重定向都基于标准数据流的原理.三个数据了分别如下: 1)标准输入--需要处理的数据流 2)标准输出--结果数据流 3)标准错误输出--错误消息流 概念:所以的Unix工具都使用文件描述符0.1和2.标准输入文件的描述符是0,标准输出的文件描述符是1,而标准错误输出的文件描述符则是2.Unix假设文件描述符0.1.2已经被打开,可以分别进行读写操作. 通常通过shell命令行运行Unix系统工具时,stdin.

《Unix环境高级编程》读书笔记 第3章-文件I/O

1. 引言 Unix系统的大多数文件I/O只需用到5个函数:open.read.write.lseek以及close 本章描述的函数经常被称为不带缓冲的I/O.术语不带缓冲指的是在用户的进程中对其不会自动缓冲,每个read和write都调用内核中的一个系统调用.但是,所有磁盘I/O都要经过内核的块缓存区(也称为内核的缓冲区高速缓存).唯一例外的是对原始磁盘设备的I/O. 2. 文件描述符 对于内核而言,所有打开的文件都通过文件描述符引用.文件描述符是一个非负整数,其变化范围是0~OPEN_MAX

《Unix环境高级编程》读书笔记 第7章-进程环境

1. main函数 int main( int argc, char *argv[] ); argc是命令行参数的数目,包括程序名在内 argv是指向参数的各个指针所构成的数组,即指针数组 当内核执行C程序时(使用exec函数),在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接器设置的,而连接器则是由C编译器调用.启动例程从内核取得命令行参数和环境变量值,然后按上述方式调用main函数做好安排. 2. 进程终止 有8种方式使进程终止,其中5种