0

QProcess を 1 Hz のタイマー スロットで実行しています。このプロセスは、Linux コマンドを呼び出し、その出力を解析するように設計されています。

問題は次のとおりです。プログラムを約 20 分間実行した後、次のエラーが発生します。

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

理想的には、このプログラムはシステムの稼働時間全体 (数日または数週間) にわたって実行されます。

例を読んでプロセス制御に注意したと思いますが、何か見落としているかもしれません。私は Qt の Web サイトの例を使用しました。それらは私が書いたものと同じコードを使用していますが、これらは数千回ではなく、1 回だけ使用するように設計されています。最小限の例を次に示します。

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()されるのは、前の実行が完了する前に呼び出された場所で呼び出しが重複する可能性があることです。

これを再構築して、トップレベル クラスのインスタンス変数ではなく、新しいQProcessオブジェクトが内部で( 'd ではgetMemoryUsage()なくスタック上で) 使用されるようにするのはどうですか? newこれにより、(オブジェクトが範囲外になる) クリーンアップが保証され、QProcess呼び出しのオーバーラップの可能性が回避されます。

または、プロセスとして呼び出し/usr/bin/freeてその出力を解析するのではなく、/proc/meminfo自分で直接読んでみませんか? これにより、はるかに効率的になります。

于 2013-04-26T14:22:20.637 に答える
1

QProcessから派生しているため、 close()QIODeviceを呼び出すと、ファイルハンドルが閉じられ、問題が解決するはずです。

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