zoukankan      html  css  js  c++  java
  • 系统调用与信号重启,好

    这篇写的很好

    http://blog.chinaunix.net/uid-24774106-id-3065234.html

    UNIX系统编程,这本书中有大量的重启系统调用,例如下面的例子:选自P50,

    pid_t r_wait(int *stat_loc)
    {
        int retval;
        while(((retval = wait(stat_loc)) ==-1 && (errno == EINTR));
        return retval;
    }

    还有对read,write的重启操作。

    UNP volume1中提到slow system call,UNP中的例子是accept系统调用,accept是服务器端接受网络客户端的连接,connect,将完成三次握手协议的连接返回。如果服务器打开了监听listen,但是始终没有客户端来连接connect,可以想见,accept就阻塞在此。这是一种比较好理解的阻塞型系统调用。

    wait也是一种阻塞性的调用。

    但是linux世界上还有另外一种东东,叫做信号,来处理突发事件。

    一般来讲,一个系统调用,要么成功,要么失败,但是由于为了及时处理信号,出现了第三种情况,系统调用被信号中断,为了标识这种情况,错误码errno置为EINTR。

    我们可以看到这种方式并不优美,程序员需要自己判断errno,如果被信号终端,那么还需要自己来重启系统调用。这是System V UNIX的实现方式。

    BSD 内核想程序员之所想,急程序员之所急,采用了另外一种实现,就是如果中断系统调用,切换到用户态来执行信号处理程序,那么系统调用没有返回值,内核在信号处理函数结束后,自动重启系统调用。这种方式很贴心阿,程序员再也不用自己判断errno,然后重启系统调用了。

     

    LINUX不愧是UNIX世界的杰出新秀,他通过SA_RESTART 就可以支持BSD方案。

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<sys/wait.h>
    #include<errno.h>
    #include<string.h>
    
    pid_t r_wait(int *stat_loc)
    {
        int ret;
            while(((ret = wait(stat_loc)) == -1) )
            {
                    /*if(errno == EINTR)
                    {
                         fprintf(stderr,"may be interrupted by a signal,let wait again 
    ");
                    }
                    else*/
                    {
                            break;
                    }
            }
    
            return ret;
    }
    
    void sig_alrm_func()
    {
        printf("catch an alarm signal
    ");
        return;
    }
    
    int main(int argc,char** argv)
    {
        pid_t childpid;
            int i,n;
            struct sigaction act;
    
            if(argc != 2)
            {
             fprintf(stderr,"usage : test n 
    ",argv[0]);
                 return -1;
            }
    
            n = atoi(argv[1]);
            
            act.sa_handler = sig_alrm_func;
            sigemptyset(&act.sa_mask);
            act.sa_flags = 0;
            // act.sa_flags |= SA_RESTART;
            sigaction(SIGALRM,&act,NULL);
            for(i = 0;i<n;i++)
            {
             if((childpid = fork()) <= 0)
                                    break;
            }
    
           if(childpid == 0 )
            {
                   sleep(50);
            }
            while(r_wait(NULL) >0) ;
            fprintf(stderr," i :%d process ID : %ld,	 parent ID :%ld 	child ID : %ld
    ",
                                            i,(long)getpid(),(long)getppid(),(long)childpid);
    
            return 0;
    }
    View Code

    原文中对比了三种方案。

    第一种,是不判断EINTR.

    第二种,是判断EINTR,然后重启。

    第三种,是对于信号处理函数,sigaction,里面sa_flags 加上对 SA_RESTART的支持,这样被中断的系统调用就能够自动重启了。

    注意,和sleep是不一样的。sleep是返回的秒数可能不足。

    http://www.cnblogs.com/charlesblc/p/6434213.html

    返回剩余的秒数,而不是errno=EINTR。

    sleep的例子应该是,SIGALARM,因为本身sleep就是用SIGALARM实现的。

  • 相关阅读:
    JS parseInt 中08.09 被按照0处理
    jsp页面修改后保存无反映,后台也没有执行到代码。
    linux setsockopt函数【转】
    gdb常用命令【转】
    C语言文件操作函数大全
    setsockopt 设置socket 详细用法 【转】
    解决VNC看不到图像的问题
    makefile【转】
    用GDB调试程序【转】
    Linux下GCC使用方法简介【转】
  • 原文地址:https://www.cnblogs.com/charlesblc/p/6492703.html
Copyright © 2011-2022 走看看