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

时间:2015-02-09 15:43:46

标签: c++ pipe inter-process-communicat

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

当我调试应用程序时,我在以下代码行中得到一个例外:

// 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;

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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

当你完成资源时,发布资源总是很好的建议。