Linux信号驱动I/O 学习记录

Q:什么是信号驱动I/O?
A:对于给定的I/O口(一般就是对于文件描述符)设定为信号驱动I/O,则当I/O口准备好之后(读:有数据可读;写:有空间可写),向注册它的进程发送事先约定好的信号,进程收到信号后触发signal handler进行I/O处理。

Q:Linux下信号驱动I/O的注册方法?
A:系统设定两种信号为专用信号:SIGIO和SIGURG,这两种都是非实时、不可靠信号,不能参加排队。前者是通用信号,后者则专门用于网络传输中带外数据(紧急数据)的I/O,本文不涉及。具体步骤如下:
1. 对文件描述符调用fcntl函数,设置O_NONBLOCK和O_ASYNC(只能对终端和网络的文件描述符使用)属性;
fcntl(fd, F_SETFL, old | O_NONBLOCK | O_ASYNC)
2. 对文件描述符设置SIGIO、SIGURG信号所通知的进程,一般是调用进程本身;
fcntl(fd, F_SETOWN, getpid())
3. 编写signal handler函数,并使用signal或sigaction函数注册。

这就是APUE书上所说的BSD异步I/O方法。严格的说信号驱动I/O不是异步的I/O,因为它I/O的操作本身仍然是同步的(需要进程主动去读取或写入),只是使用了signal这种异步机制通知进程什么时候该读写了,属于伪异步。

实验一:将标准输入注册为信号驱动I/O

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 

    void sigio_handler(int sig)
    {
        static int cnt = 0;

        printf("receive SIGIO signal %d\n", ++cnt);
        fflush(stdin);
        fflush(stdout);
    }


    int main(int argc, char **argv)
    {
        struct sigaction sig_act;
        int fl = 0;

        //signal driven I/O setting
        fflush(stdin);
        fflush(stdout);
        fl = fcntl(STDIN_FILENO, F_GETFL, 0);
        fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK | O_ASYNC );
        fcntl(STDIN_FILENO, F_SETOWN, getpid());
        sigemptyset(&sig_act.sa_mask);
        sig_act.sa_flags = 0;
        sig_act.sa_handler = sigio_handler;
        sigaction(SIGIO, &sig_act, NULL);

        printf("test start\n");
        fflush(stdin);
        fflush(stdout);

        while (1)
        {
            sleep(1);
        }

        return 0;
    }

实验结果:循环打印signal handler中的语句,如下:

test start
receive SIGIO signal 1
receive 

你可能感兴趣的:(linux编程,linux,signal,I-O)