QProcess,无法创建管道

时间:2013-04-26 13:00:20

标签: c++ linux qt qprocess

我在1 Hz的定时器插槽中运行QProcess。该过程旨在唤起Linux命令并解析其输出。

问题是:程序运行大约20分钟后,我收到此错误:

QProcessPrivate::createPipe: Cannot create pipe 0x104c0a8: Too many open files
QSocketNotifier: Invalid socket specified

理想情况下,此程序将在整个系统正常运行时间内运行,可能需要数天或数周。

我认为通过阅读示例我一直小心过程控制,但也许我错过了一些东西。我使用过Qt网站上的例子,他们使用的是我编写过的相同代码,但这些代码仅供一次使用,而不是数千次。这是一个最低限度的例子:

class UsageStatistics : public QObject {
    Q_OBJECT 
public:
    UsageStatistics() : process(new QProcess) {
       timer = new QTimer(this);
       connect(timer, SIGNAL(timeout()), this, SLOT(getMemoryUsage()));
       timer->start(1000); // one second
    }

    virtual ~UsageStatistics() {}

public slots:

    void getMemoryUsage() {
        process->start("/usr/bin/free");
        if (!process->waitForFinished()) {
            // error processing
        }

        QByteArray result = process->realAll();
        // parse result 

        // edit, I added these
        process->closeReadChannel(QProcess::StandardOutput);
        process->closeReadChannel(QProcess::StandardError);
        process->closeWriteChannel();
        process->close();
    }
}

我还尝试在函数末尾手动deleting进程指针,然后在开头尝试new。我想,值得一试。

免费啤酒,无论谁回答这个问题:)

4 个答案:

答案 0 :(得分:1)

QProcess派生自QIODevice,因此我要说调用close()应关闭文件句柄并解决问题。

答案 1 :(得分:1)

我看不出这个问题,但是有一点让我担心的是getMemoryUsage()中可能的调用重叠,它在上一次运行完成之前被调用。

如何重组这个以便在QProcess(在堆栈中,而不是getMemoryUsage()'d)内使用新的new对象,而不是作为顶层的实例变量等级?这将确保清理(QProcess对象超出范围)并避免任何可能的调用重叠。

或者,不是将/usr/bin/free作为进程调用并解析其输出,为什么不直接阅读/proc/meminfo?这将更多更有效率。

答案 2 :(得分:1)

首先我和你有同样的情况。我得到了相同的结果。 我认为QProcess无法正确处理打开的管道。

然后,我决定使用popen()+ QFile()而不是QProcess。

class UsageStatistics : public QObject {
Q_OBJECT 
public:
UsageStatistics(){
   timer = new QTimer(this);
   connect(timer, SIGNAL(timeout()), this, SLOT(getMemoryUsage()));
   timer->start(1000); // one second
}

virtual ~UsageStatistics() {}

private:
    QFile freePipe;
    FILE *in;

public slots:

void getMemoryUsage() {

    if(!(in = popen("/usr/bin/free", "r"))){
            qDebug() << "UsageStatistics::getMemoryUsage() <<" << "Can not execute free command.";
            return;
    }

    freePipe.open(in, QIODevice::ReadOnly);
    connect(&freePipe, SIGNAL(readyRead()), this, SLOT(parseResult()) );
    // OR waitForReadyRead() and parse here.
}

void parseResult(){
    // Parse your stuff
    freePipe.close();
    pclose(in); // You can also use exit code by diving by 256.
}
}

答案 3 :(得分:0)

tl; dr:
发生这种情况是因为您的应用程序要使用的资源超出了系统范围的资源限制所允许的范围。如果您有大型应用程序,则可以使用[2]中指定的命令来解决此问题,但这可能是由于编程错误引起的。


我自己也解决了类似的问题。我使用QThread记录QProcesses的退出代码。 QThread使用curl连接到FTP服务器上载日志。由于我正在测试软件,因此我没有连接FTP服务器,而curl_easy_perform显然在等待连接。因此,达到了我的资源限制,并且出现了此错误。一段时间后,我的程序开始抱怨,这是找出问题所在的主要指标。

[..]
QProcessPrivate::createPipe: Cannot create pipe 0x7fbda8002f28: Too many open files
QProcessPrivate::createPipe: Cannot create pipe 0x7fbdb0003128: Too many open files
QProcessPrivate::createPipe: Cannot create pipe 0x7fbdb4003128: Too many open files
QProcessPrivate::createPipe: Cannot create pipe 0x7fbdb4003128: Too many open files
[...]
curl_easy_perform() failed for curl_easy_perform() failed for disk.log
[...]

此错误发生后,我已通过将机器连接到FTP服务器来测试此问题。那解决了我的问题。

阅读:
[1] https://linux.die.net/man/3/ulimit
[2] https://ss64.com/bash/ulimit.html
[3] https://bbs.archlinux.org/viewtopic.php?id=234915