1

I'm trying to use QProcess inside a thread to do some operations (read I2C connections).The update method is calling every 100 msec:

void TempsReader::update()
{
    if (_currProcess == nullptr) {
        _currProcess = new QProcess();
        connect(_currProcess, &QProcess::errorOccurred, this, &TempsReader::onProcessError);
        connect(_currProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
                this, SLOT(onProcessFinished()));
    }

    _currProcess->start("sh");
    if (_currProcess->waitForStarted()) {
        _currProcess->write("i2cdetect -y 1");
        _currProcess->closeWriteChannel();
        _currProcess->waitForFinished();
    }
}

After some time, the process gives "FailedToStart" error and never starts again.

enter image description here

void TempsReader::onProcessError(QProcess::ProcessError error)
{
    qDebug() << error;
    _currProcess->close();
}

void TempsReader::onProcessFinished()
{
    QString devs = _currProcess->readAll();
    _currProcess->waitForFinished();
    // doing some stuff with devs
    _currProcess->close();
}

How can I fix this issue? Am I using QProcess in a wrong way? and how can I start the process again when it drops in error slot. Thanks in advance.

Update: QProcess::errorString() gives this: "Resource error (fork failure): Too many open files"

enter image description here

UPDATE: Finally I've found the issue and it was not related to QProcess itself. It was relating to I2C connection.

Mosi
  • 1,178
  • 2
  • 12
  • 30
  • 1
    What does [`QProcess::errorString()`](https://doc.qt.io/qt-5/qiodevice.html#errorString) say? – acraig5075 Dec 18 '19 at 13:12
  • 2
    There are several issues could happen. First of all, try to get the output of the process with `readAllStandardError` and `readAllStandardOutput` to see if the command (i2cdetect) is returning some errors. Also, get the `state` of the process to see if it finished, if not you maybe have to `terminate` or `kill` the process. And, you probably need to `delete _currProcess;` after ending it. – user1810087 Dec 18 '19 at 13:13
  • 1
    I think the failure is because your `update()` function is called several times but work on the same `QProcess`. If you call `update()`, you start the process, fine. But if you call `update()` again without ensuring the previous `update()` has finished (still waiting for the end of the process), you will try to start an already started process (because you uses the same `QProcess` object) and therefore the start will fail. – Fareanor Dec 18 '19 at 13:29
  • 1
    @acraig5075 Good Point! : "Resource error (fork failure): Too many open files" – Mosi Dec 18 '19 at 15:19
  • @user1810087 readAllStandardError/Output gives nothing! – Mosi Dec 18 '19 at 15:32
  • @user1810087 But I don't. I think the problem is that I'm opening too much 'sh' with update method. – Mosi Dec 18 '19 at 15:48
  • @user1810087 Maybe I should change codes so that "_currProcess->start("sh");" runs only once – Mosi Dec 18 '19 at 15:49
  • Can you check how many threads the process is using. – user1810087 Dec 18 '19 at 16:02
  • @user1810087 How can I check that? I'm running on a rasp – Mosi Dec 18 '19 at 16:03
  • rasp = raspberry? os raspbian? https://stackoverflow.com/questions/268680/how-can-i-monitor-the-thread-count-of-a-process-on-linux – user1810087 Dec 18 '19 at 16:07
  • @user1810087 yes raspberry. the total threads for my app is fixed and is 10. It's not increasing with time – Mosi Dec 18 '19 at 16:12

2 Answers2

2

My guess is that you get the failure because all your update() calls share the same QProcess object.

What happens here is that when you call update(), you start the process. And 100ms later, you call it again without ensuring that the previous update() has finished to wait the end of the process.
The consequence is that you try to start an already started process and thus it fails.

For me, the easiest solution is to create one QProcess object for each update() call.
Something like:

void TempsReader::update()
{
    QProcess * current_process = new QProcess;

    connect(current_process, &QProcess::errorOccured, this, &TempReader::onProcessError);
    connect(current_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &TempReader::onProcessFinished());

    current_process->start("sh"); // Your command
    current_process->waitForStarted();
    current_process->write("i2cdetect -y 1");
    current_process->waitForFinished();

    current_process->deleteLater();
}

Or without pointers:

void TempsReader::update()
{
    QProcess current_process;

    connect(&current_process, &QProcess::errorOccured, this, &TempReader::onProcessError);
    connect(&current_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &TempReader::onProcessFinished());

    current_process.start("sh"); // Your command
    current_process.waitForStarted();
    current_process.write("i2cdetect -y 1");
    current_process.waitForFinished();
}

As you did not show the calling part of the code (the thread creation, the 100ms loop, ...), this may not be the solution you need.
In this case, please let me know if it does not solve your issue so that I'll remove this answer.

Fareanor
  • 5,900
  • 2
  • 11
  • 37
  • Thanks for sharing your thoughts. I've already tested this solution but not helped :( But please don't remove it. Maybe I'll come with a similar solution and will update you. – Mosi Dec 18 '19 at 15:04
0

Finally I've found the issue and it was not related to QProcess itself. It was relating to I2C connection. I was using this command in update: wiringPiI2CSetup(addr); and it opens a new device each time.

Mosi
  • 1,178
  • 2
  • 12
  • 30