2013-04-26 178 views
0

我正在1赫兹的计时器插槽中运行QProcess。该过程旨在唤起Linux命令并解析其输出。QProcess,无法创建管道

问题是这样的:节目约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开头。我想这是值得一试的。

免费啤酒谁回答了这个:)

+0

您在某处泄漏句柄,或者您同时启动了太多QProcess-es。看到https://bugreports.qt-project.org/browse/QTBUG-18934 – sashoalm 2013-04-26 13:44:22

+0

这不是你的问题的答案,但如果你的目标是要找出系统中有多少内存是空闲的,我建议完全避免QProcess并使用更轻量级的机制,如fopen(“/ proc/meminfo”,“r”),并直接读出数据。效率更高,错误更少:) – 2013-04-26 14:47:09

回答

1

QProcessQIODevice得来,所以我会说打电话close()应该关闭文件句柄并解决你的问题。

+0

直接运行16:00,然后出现相同错误,即使使用'close()' – 2013-04-26 13:49:19

1

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

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

另外,为什么不直接自己读/proc/meminfo作为一个过程并解析其输出,而不是调用/usr/bin/free?这将是更有效率。

+0

我并不直接直接读取'/ proc/meminfo',因为解析起来更加困难。实际上我有一个功能,但是当进行基准测试时,我发现性能差异可以忽略不计,所以我选择了易于理解的代码。但是,如果'QProcess'不能平移,我只会使用原始的解析函数。 – 2013-04-26 16:21:53

+0

系统调用[sysinfo](http://man7.org/linux/man-pages/man2/sysinfo.2.html)如何?这个调用还会返回linux上的可用内存。 – cloose 2013-04-26 17:03:13

1

首先我和你有同样的情况。我得到了同样的结果。 我认为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. 
} 
}