Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么不能为Linux非阻塞套接字递归调用“select”_C_Linux_Recursion - Fatal编程技术网

为什么不能为Linux非阻塞套接字递归调用“select”

为什么不能为Linux非阻塞套接字递归调用“select”,c,linux,recursion,C,Linux,Recursion,我正在使用“old school”SELECT在Linux上实现一个非阻塞UDP套接字。基本上,我有一个线程正在运行以下函数: int NBRecv(void* pv, size_t len){ int res = -1; FD_ZERO(&select_socks); FD_SET(sock, &select_socks); int readsocks = select(sock + 1, &select_socks, (fd_s

我正在使用“old school”SELECT在Linux上实现一个非阻塞UDP套接字。基本上,我有一个线程正在运行以下函数:

int NBRecv(void* pv, size_t len){
    int res = -1;
    FD_ZERO(&select_socks);    
    FD_SET(sock, &select_socks);
    int readsocks = select(sock + 1, &select_socks, (fd_set *)0, (fd_set *)0, &select_timeout);
    assert(readsocks >= 0);
    if(readsocks == 0)
        return NBRecv(pv, len);
    else {
        if(FD_ISSET(sock, &select_socks)){
            res = read(sock, pv, len);
        }
        else
            res = 0;
        return res;
    }
}
在上面你可以看到,如果没有套接字可供读取继续等待,我将再次调用该函数。我知道这是一个无限循环。但是,每次运行这个函数时,我都会遇到一个分段错误,特别是在运行递归调用时。删除递归调用后,一切正常

我天真的理解是,这里的递归与while循环没有什么不同


有谁能帮我解释一下为什么会发生这种错误吗?

与while循环不同,递归可以†根据调用堆栈的深度按比例占用堆栈空间。递归调用越多,使用的堆栈空间就越多。最终,您的程序会耗尽堆栈空间并崩溃

使用while循环


†我之所以说可以,是因为可以对进行优化,将尾部调用转化为简单的跳转,并消除无限内存使用。这是一个特例;它不适用于所有递归调用。也不能依赖它,因为C语言不要求编译器执行尾部调用消除。

与while循环不同,递归可以†根据调用堆栈的深度按比例占用堆栈空间。递归调用越多,使用的堆栈空间就越多。最终,您的程序会耗尽堆栈空间并崩溃

使用while循环


†我之所以说可以,是因为可以对进行优化,将尾部调用转化为简单的跳转,并消除无限内存使用。这是一个特例;它不适用于所有递归调用。也不能依赖它,因为C语言对编译器没有执行尾部调用消除的要求。

您应该使用并阅读关于1的内容,选择超时从何而来?2选择返回-1不一定是错误,在抛出crawbar之前先检查errno。@basilestrynkevitch谢谢!我将研究poll和最近的非阻塞套接字函数。我在这里使用select是因为我们的连接数量相当少。@wildplasser:也可以使用select\u socks。还有袜子,但没人知道袜子的地址。至于select返回-1,我认为从技术上讲,EINTR是一个错误,但它肯定不值得断言。@wildplasser谢谢。我会找到更好的方法来处理返回值。timeout变量是预定义的timeval结构。我实际上已经将其更改为该函数的一个局部变量,因为我被告知select函数修改传递给它的timeval结构。您应该使用&阅读关于1的内容select_timeout从何而来?2选择返回-1不一定是错误,在抛出crawbar之前先检查errno。@basilestrynkevitch谢谢!我将研究poll和最近的非阻塞套接字函数。我在这里使用select是因为我们的连接数量相当少。@wildplasser:也可以使用select\u socks。还有袜子,但没人知道袜子的地址。至于select返回-1,我认为从技术上讲,EINTR是一个错误,但它肯定不值得断言。@wildplasser谢谢。我会找到更好的方法来处理返回值。timeout变量是预定义的timeval结构。实际上,我已经将其更改为该函数的一个局部变量,因为我被告知select函数修改传递给它的timeval结构。当然,不能保证,C不是Scheme。在-O2中,gcc对发布的代码进行尾部调用优化。当然,没有保证,C不是方案。