QProcess,无法创建管道

Posted

技术标签:

【中文标题】QProcess,无法创建管道【英文标题】:QProcess, Cannot Create Pipe 【发布时间】:2013-04-26 13:00:20 【问题描述】:

我正在以 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开头。我想这值得一试。

回答这个问题的人可以免费喝啤酒:)

【问题讨论】:

您在某处泄漏句柄,或者您同时启动了太多 QProcess-es。见bugreports.qt-project.org/browse/QTBUG-18934 这不是您问题的答案,但如果您的目标是找出系统中有多少可用内存,我建议完全避免使用 QProcess 并使用更轻量级的机制,例如fopen("/proc/meminfo", "r") 直接读出数据。更高效,更不容易出错:) 【参考方案1】:

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

【讨论】:

运行精确到 16:00,然后出现同样的错误,即使使用 close()【参考方案2】:

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

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

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

【讨论】:

我没有直接阅读/proc/meminfo,因为它更难解析。我实际上有一个函数可以做到这一点,但是在进行基准测试时,我发现性能差异可以忽略不计,所以我选择了易于理解的代码。但是,如果QProcess 不成功,我将使用原始的解析函数。 系统调用sysinfo呢?此调用还返回 linux 上的空闲内存。【参考方案3】:

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

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

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.


【讨论】:

【参考方案4】:

tl;博士: 发生这种情况是因为您的应用程序想要使用比系统范围资源限制所允许的更多的资源。如果你有一个庞大的应用程序,你可能可以使用[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

【讨论】:

以上是关于QProcess,无法创建管道的主要内容,如果未能解决你的问题,请参考以下文章

使用 QProcess 进行管道(或命令链接)

QProcess与外部程序的调用(可以通过设置管道来交互)

Qt笔记-QProcess带管道符号运行及获取进程启动时间(Linux)

Qt笔记-QProcess带管道符号运行及获取进程启动时间(Linux)

QProcess 无法执行简单的控制台程序

QProcess 执行一个 c++ 文件