C++ 管道,打开的文件太多,Errno 25

Posted

技术标签:

【中文标题】C++ 管道,打开的文件太多,Errno 25【英文标题】:C++ Pipe, Too Many Open Files, Errno 25 【发布时间】:2015-02-09 15:43:46 【问题描述】:

我有一个在 OS X (10.10/Yosemite) 上运行的旧 C++ 应用程序。

当我调试应用程序时,以下代码行出现异常:

// create pipe
    int pipefd[2];
    int piperet = pipe(pipefd);
    if( piperet )
    
        wcsncpy(errbuf, CEmpError::GetErrorText(CEmpError::ERR_SYSTEM, L"Can't create pipe for IPC.", errno).c_str(), errbuflen);
        CEmpError::LogError(errbuf);
        return CEmpError::ERR_SYSTEM; //= 115
    

所以应用程序正在运行并执行这行代码几次。过了一会儿pipette-1errno 错误代码是 25。

经过一番研究,这意味着“打开的文件太多”。是否有解决方法来关闭所有这些打开的文件?还是可以知道哪些文件打开的太多?

当我输入终端 ulimit -a 时,我得到:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 2560
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

所以我不是超级c++-pro,这里需要的代码行。猜猜所有不需要的管道或 pipefd 将被关闭。

// create pipe
    int pipefd[2];
    int piperet = pipe(pipefd);
    if( piperet )
    
        wcsncpy(errbuf, CEmpError::GetErrorText(CEmpError::ERR_SYSTEM, L"Can't create pipe for IPC.", errno).c_str(), errbuflen);
        CEmpError::LogError(errbuf);
        return CEmpError::ERR_SYSTEM;
    

    CEmpError *pError = 0;

    // after transfer the execution bit could be reset, so set the rights back
    chmod(args[0], S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH );

    pid_t pid = fork();
    if(pid == 0)
     // child process

        close(pipefd[0]); // close reading end
        int fd = pipefd[1];

        // redirect stdout and stderr to pipe
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);

    close(fd); // not needed anymore

        // execute steup.sh with built argument list
        execvp(args[0], (char**)args);

        // if we ever reached this line the exec failed and we need to report error to parent process
        // once we are in child process we will print the error into stdout of our child process
        // and parent process will parse and return it to the caller.
        char buf[128];
        sprintf(buf, "setup.sh:ERROR:PI%03d",CEmpError::ERR_EXEC);

        perror(buf);

        // keep the process alive until the parent process got the error from the pipe and killed this child process
        sleep(5);

        return CEmpError::ERR_EXEC;
    
    else if (pid > 0)
     // parent process
        delete[] args[0]; // release memory allocated to f.
        delete[] args[3]; // release memory allocated to log f.
        delete[] args[5]; // release memory allocated to pn
        close(pipefd[1]);

        pParser = new CPackageInstallerParser();

        FILE* fp = fdopen(pipefd[0], "r");
        /*int res = */setvbuf(fp, NULL, _IOLBF, 0);

        try 
        
            pParser->ParseOutput(fp, statusCallback, statusContext, logFileName);
        
        catch (CEmpError* pErr) 
        
            if (pErr->ErrorCode == CEmpError::ERR_EXEC)
                kill(pid, SIGABRT); // the error is parsed kill the child process
            pError = pErr;
        
        catch (...) 
        
            // some exception from statusCallback
            fclose(fp);
            delete pParser;
            pParser = NULL;
            throw;
        

        fclose(fp);

        int stat;
        // wait for the installation process to end.
        waitpid(pid, &stat, 0);

        if (WIFEXITED(stat) && (stat % 256 == 0) && pError == NULL) 
        
            // exited normally with code 0 (success)
            // printf("Installed succesfully!\n");

            // register succesful operation result
            try 
            
                RegisterResult(operation);
            
            catch (CEmpError* pErr) 
            
                pError = pErr;
            
        
        else 
        
            if (pError == NULL) // no error was caught by parser
                pError = new CEmpError(CEmpError::ERR_UNKNOWN);
            //dumpError(stat);
        
    
    else
        pError = new CEmpError(CEmpError::ERR_FORK);


    //clean up and exit
    if (pParser != NULL)
        delete pParser;
    pParser = NULL;

    int exitcode = 0;
    if (pError != NULL)
    
        exitcode = pError->ErrorCode;
        wcsncpy(errbuf, pError->GetErrorText().c_str(), errbuflen);
        pError->Log();
        delete pError;
    
    return exitcode;

【问题讨论】:

【参考方案1】:

当您不再需要管道 FD 时,需要使用 close 关闭它们。

【讨论】:

uao.混合 C 错误与 C++ 异常!看起来一团糟【参考方案2】:

每个进程允许您打开 2560 个文件,因此您应该在不再需要时关闭其他文件和/或管道。

用完资源后释放资源总是好的建议。

【讨论】:

我认为“软限制”是 2560,而“硬限制”是无限的 ulimit -Snulimit -Hn 告诉我。 无论是软限制还是硬限制,看起来你打开了很多文件。所以无论哪种情况,都要小心你消耗的资源。

以上是关于C++ 管道,打开的文件太多,Errno 25的主要内容,如果未能解决你的问题,请参考以下文章

Qt 上的“GLib-ERROR **:无法创建管道主循环唤醒:打开的文件太多”

如何解决打开文件时出现IOError[errno 17]文件?

linux c 打开文件 errno 13

Django Heroku:python:无法打开文件'manage.py':[Errno 2]没有这样的文件或目录

[Errno -101] NetCDF:打开 netcdf 文件时出现 HDF 错误

用 C++ 打开 2 个数据文件