0

我在 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

4 回答 4

1

我看不到这个问题,但是我担心的一件事是getMemoryUsage()在上一次运行完成之前调用它的位置可能存在调用重叠。

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

或者,与其/usr/bin/free作为一个进程调用并解析它的输出,为什么不/proc/meminfo自己直接读取呢?这将更有效率。

于 2013-04-26T14:22:20.637 回答
1

QProcess派生自QIODevice,所以我会说调用close()应该关闭文件句柄并解决您的问题。

于 2013-04-26T13:18:33.957 回答
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.
}
}
于 2015-05-12T10:21:18.100 回答
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

于 2019-08-15T09:06:46.093 回答