zoukankan      html  css  js  c++  java
  • linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式

        一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是让系统调用失败?早期UNIX系统的做法是, 中断系统调用, 并让系统调用失败, 比如read返回 -1, 同时设置 errno 为 EINTR中断了的系统调用是没有完成的调用, 它的失败是临时性的, 如果再次调用则可能成功, 这并不是真正的失败, 所以要对这种情况进行处理, 典型的方式为:

    while (1) {
    
        n = read(fd, buf, BUFSIZ);
    
        if (n == -1 && errno != EINTR) {
    
            printf("read error
    ");
    
            break;
    
        }
    
        if (n == 0) {
    
            printf("read done
    ");
    
            break;
    
        }
    
    }

    这样做逻辑比较繁琐, 事实上, 我们可以从信号的角度来解决这个问题,  安装信号的时候, 设置 SA_RESTART属性, 那么当信号处理函数返回后, 被该信号中断的系统调用将自动恢复.

    示例程序:

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <error.h>
    #include <string.h>
    #include <unistd.h>
    
    void sig_handler(int signum)
    {
        printf("in handler
    ");
        sleep(1);
        printf("handler return
    ");
    }
    
    int main(int argc, char **argv)
    {
        char buf[100];
        int ret;
        struct sigaction action, old_action;
    
        action.sa_handler = sig_handler;
        sigemptyset(&action.sa_mask);
        action.sa_flags = 0;
        /* 版本1:不设置SA_RESTART属性
         * 版本2:设置SA_RESTART属性 */
        //action.sa_flags |= SA_RESTART;
    
        sigaction(SIGINT, NULL, &old_action);
        if (old_action.sa_handler != SIG_IGN) {
            sigaction(SIGINT, &action, NULL);
        }
    
        bzero(buf, 100);
    
        ret = read(0, buf, 100);
        if (ret == -1) {
            perror("read");
        }
    
        printf("read %d bytes:
    ", ret);
        printf("%s
    ", buf);
    
        return 0;
    }

    当sa_flags不设置:SA_RESTART时:

    结果:

    QQ截图20130715193553

    设置后:

    当被中断后,重新执行

    QQ截图20130715193845

    man帮助说明:

    Interruption of system calls and library functions by signal handlers
           If a signal handler is invoked while a system call or library
           function call is blocked, then either:
    
           * the call is automatically restarted after the signal handler
             returns; or
    
           * the call fails with the error EINTR.
    
           Which of these two behaviors occurs depends on the interface and
           whether or not the signal handler was established using the
           SA_RESTART flag (see sigaction(2)).  The details vary across UNIX
           systems; below, the details for Linux.
    
           If a blocked call to one of the following interfaces is interrupted
           by a signal handler, then the call will be automatically restarted
           after the signal handler returns if the SA_RESTART flag was used;
           otherwise the call will fail with the error EINTR:
    
               * read(2), readv(2), write(2), writev(2), and ioctl(2) calls on
                 "slow" devices.  A "slow" device is one where the I/O call may
                 block for an indefinite time, for example, a terminal, pipe, or
                 socket.  (A disk is not a slow device according to this
                 definition.)  If an I/O call on a slow device has already
                 transferred some data by the time it is interrupted by a signal
                 handler, then the call will return a success status (normally,
                 the number of bytes transferred).
    
               * open(2), if it can block (e.g., when opening a FIFO; see
                 fifo(7)).

    * wait(2), wait3(2), wait4(2), waitid(2), and waitpid(2). * Socket interfaces: accept(2), connect(2), recv(2), recvfrom(2), recvmsg(2), send(2), sendto(2), and sendmsg(2), unless a timeout has been set on the socket (see below). * File locking interfaces: flock(2) and fcntl(2) F_SETLKW. * POSIX message queue interfaces: mq_receive(3), mq_timedreceive(3), mq_send(3), and mq_timedsend(3). * futex(2) FUTEX_WAIT (since Linux 2.6.22; beforehand, always failed with EINTR). * POSIX semaphore interfaces: sem_wait(3) and sem_timedwait(3) (since Linux 2.6.22; beforehand, always failed with EINTR). The following interfaces are never restarted after being interrupted by a signal handler, regardless of the use of SA_RESTART; they always fail with the error EINTR when interrupted by a signal handler: * Socket interfaces, when a timeout has been set on the socket using setsockopt(2): accept(2), recv(2), recvfrom(2), and recvmsg(2), if a receive timeout (SO_RCVTIMEO) has been set; connect(2), send(2), sendto(2), and sendmsg(2), if a send timeout (SO_SNDTIMEO) has been set.
           * Interfaces used to wait for signals: pause(2), sigsuspend(2),
                 sigtimedwait(2), and sigwaitinfo(2).
    
               * File descriptor multiplexing interfaces: epoll_wait(2),
                 epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).
    
               * System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and
                 semtimedop(2).
    
               * Sleep interfaces: clock_nanosleep(2), nanosleep(2), and
                 usleep(3).
    
               * read(2) from an inotify(7) file descriptor.
    
               * io_getevents(2).
    
           The sleep(3) function is also never restarted if interrupted by a
           handler, but gives a success return: the number of seconds remaining
           to sleep.
  • 相关阅读:
    android 入门-Service
    android 入门-Activity及 字体
    android 入门-安装环境
    PS 零基础训练1
    wp8 入门到精通 ImageCompress 图片压缩
    wp8 入门到精通 Gallery
    C# DateTime时间格式转换为Unix时间戳格式
    wp8 入门到精通 MultiMsgPrompt
    C# Func<T,TResult>
    redis简介
  • 原文地址:https://www.cnblogs.com/mickole/p/3191832.html
Copyright © 2011-2022 走看看