If I reuse a QProcess variable, can there be leftover data in the stdout/stderr channels? - qt

I have the following scenario:
QProcess*p;
// later
p->start();
//later
p->terminate(); // there might be unread data in stdout
//later
p->start();
I read the process stdout. After I call p->start() the second time, could there still be unread data left in the stdout buffers from the first p->start()? That would be a problem for me. Do I need to flush the buffers or something?

Okay, I've checked the sources. The QProcess::start() method explicitly clears both output buffers, so it should be okay, at least in this sense:
void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
{
Q_D(QProcess);
if (d->processState != NotRunning) {
qWarning("QProcess::start: Process is already running");
return;
}
#if defined QPROCESS_DEBUG
qDebug() << "QProcess::start(" << program << "," << arguments << "," << mode << ")";
#endif
d->outputReadBuffer.clear();
d->errorReadBuffer.clear();
I still think it's a bad style to reuse the same object, though.

Related

Strange signal/slot behaviour

(Working with Qt 5.15.2)
I have a method which receives a signal (sig_responseReady) from the same thread. The purpose of this method is to wait until a response is received. While this method is waiting for the signal, the method is called again because of an event which calls this method (so eventloops get nested). However, the first waitForResponse on the stack does not get the sig_responseReady signal for up to 10 seconds (for no reason I can see), while later called waitForResponse get their signal first.
The result of this design is that I have nested eventloops, which according to this stackoverflow post causes slot/signal handling errors, and should be avoided. I suspect this is the cause of my problem.
Is there a design which accomplishes the same, with only a single eventloop? (I can't come up with it) The function which calls waitForResponse must pause until waitForResponse returns. ..I can't make it asynchronous. I tried replacing eventloop.exec with QCoreApplication::processEvents(QEventLoop::AllEvents,100) in the function below, but still get same strange result. (So maybe nested event loops is not the problem...but I can't figure out the cause)
MyClass::SRequest MyClass::waitForResponse(const QUuid queryID) {
reentryCount++; // Static var to determing nesting/depth count
QEventLoop eventloop;
qDebug() << "MyClass::waitForResponse connect for uid " << queryID << ", depth " << reentryCount;
connect(this,&MyClass::sig_responseReady,&eventloop, &QEventLoop::quit); //, Qt::QueuedConnection); // Allow matching response to stop eventloop
do {
eventloop.exec();
qDebug() << "MyClass::waitForResponse got signal for uid " << queryID;
} while (!queryResponseReady(queryID) && !queryExpired(queryID));
qDebug() << "MyClass::waitForResponse exitted loop for signal for uid " << queryID << ", depth " << reentryCount;
reentryCount--;
return queryTakeResult(queryID);
}

What is the reason asio doesn't do any delay?

I am new to asio.
Here is guide I was following writing my daytime tcp-server: https://think-async.com/Asio/asio-1.18.1/doc/asio/tutorial/tutdaytime3.html . I was trying to reproduce a reasonable example that would show that asunchronous code is actually asynchronous. I didn't modify anything else, just small piece of code in tcp_server class. I am adding this delay in order to see that after we are waiting timer to expire, we can gracefully handle other client connections/requests. So, did I miss something? Because in my case delay basically doesn't work ;(
void handle_accept(const tcp_connection::pointer &new_connection,
const asio::error_code &error) {
asio::steady_timer timer(io_context_, asio::chrono::seconds(5));
std::cout << "Before timer" << std::endl;
timer.async_wait(std::bind(&tcp_server::handle_wait, this, error, new_connection));
}
void handle_wait(asio::error_code &ec, const tcp_connection::pointer &new_connection) {
if (!ec) {
new_connection->start();
}
std::cout << "Inside timer" << std::endl;
start_accept();
}
void handle_accept(const tcp_connection::pointer &new_connection,
const asio::error_code &error) {
asio::steady_timer timer(io_context_, asio::chrono::seconds(5));
std::cout << "Before timer" << std::endl;
timer.async_wait(std::bind(&tcp_server::handle_wait, this, error, new_connection));
}
The timer is a local variable.
async_wait returns immediately, without blocking.
The function exits, destructing the timer. The timer cancels all pending operations (with error::operation_aborted).
🖛 Make sure the lifetime of the timer extends well enough to allow for it expire (or at least until it stops being relevant). In your case there will probably already be a tcp::acceptor member in your class, and the timer could reside next to it.

Resource temporarily unavailable

Consider this thread, it acts like a timer, send some packet to serial:
void PlCThead::run()
{
while(1)
{
const char str[]={UPDATE_PACKET};
QByteArray built;
built.append(0x02);
built.append(0x05);
built.append(0x03);
emit requestForWriteAndReceive(built);
msleep(100);
}
}
emit works fine, it goes inside the slot, there, it writes only 78 or char x to serial instead of a packet of 3 bytes.
bool RS::rs_ThreadPlcDataAqustn(QByteArray byteArray)
{
QByteArray rd15Bytes;
char *data = byteArray.data();
int len = byteArray.length();
if(!rs_serialWrite(data, len))
{
qDebug() << "Failure:( rs_dataqustn: rs_plcWrite(data, len)";
emit plc_port_dscntd();
return false;
}
}
bool RS::rs_serialWrite(char* buff, size_t length)
{
int tries;
int len;
tries = 0;
QByteArray built((char*)buff, length);
qDebug() << built.toHex();
len = write(fd, buff, length);
qDebug() << len;
qDebug() << strerror(errno);
return true;
}
this is how fd created:
fd = open(portPath, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK, S_IWUSR | S_IRUSR | S_IXUSR);
this is how the thread created in mainwindow:
rs_plc->rs_plcOpenPort((char *)"/dev/ttyS0"); /*/dev/ttyS3*/
PlCThead *thread = new PlCThead();
connect(thread, SIGNAL(requestForWriteAndReceive(QByteArray)), rs_plc, SLOT(rs_ThreadPlcDataAqustn(QByteArray )));
thread->start();
rs_plc is a private member of MainWindow.
strerror returns back this warning:
> Resource temporarily unavailable
any ideas? this code works fine with timers, it has been checked and tested accurately, but now i need to add this thread instead of the timer. Thanks
Your question isn't complete enough for a full diagnosis since you aren't showing how fd is created, how the threads are set up (which you say is part of the problem), etc.
But... your resource temporarily unavailable line is a big hint. The write() function isn't succeeding to write everything because it's returning an error (probably EAGAIN or EWOULDBLOCK). The fd file descriptor is attached to something that either has a small buffer, no buffer, or a buffer which is already full. And it's full, and it's the applications job to not send it anything else until it can handle it. A common thing to do there is to sleep and then try the write again if the error code is EAGAIN or EWOULDBLOCK.
But, you said it's returning 3, which actually indicates "no error" too. And if that's the case then the error string won't be referring to write itself, and something else set errno previously. (which could have been write itself in the past).
In short, if this is getting called more than once (likely) you probably need to watch out for writing too fast (and it looks like a serial buffer, which definitely falls into the category of easy-to-fill-the-buffer).
In short: if it's not writing all the bytes to the fd than you want, it's because it can't handle more than that.
This likely has absolutely nothing to do with qt by the way. It's all about the write() call.

QFileSystemModel and QFileSystemWatcher delete from disk

I have a QTreeView which is populated through a reimplementation of QFileSystemModel. As far as I know, QFileSystemModel installs a QFileSystemWatcher on the rootPath. What I'm trying to do is notify in my program when a file is being deleted directicly on the rootPath but i havent found any signal o reimplemented function which provides me that information.
My application upload some files thrugh an ftp connection and when the file is fully uploaded i remove it from the location, so i want a notification from the reimplementation of QFileSystemModel when the file is deleted directicly (not from the remove method or something similar).
I Hope you can help me. I have searched a lot on the web but I cant find anything.
Cheers.
You can use the FileSystemModel's rowsAboutToBeRemoved signal (inherited from QAbstractItemModel).
It will be fired whenever a row is removed from the model. The parent, start and end parameters allow you to get to the filename (in column 0 of the children).
Sample code:
// once you have your model set up:
...
QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
receiver, SLOT(toBeRemoved(const QModelIndex&, int, int)));
...
// in receiver class:
public slots:
void toBeRemoved(const QModelIndex &parent, int start, int end) {
std::cout << start << " -> " << end << std::endl;
std::cout << parent.child(start, 0).data().typeName() << std::endl;
std::cout << qPrintable(parent.child(start, 0).data().toString()) << std::endl;
}
(Using std::cout isn't good practice with Qt I think, this is just to get you started.)
The other aboutToBe... signals from QAbstractItemModel can be used for the other events that happen on the filesystem.

qt - qprocess start in a loop

I am calling a process in a loop. Need to ensure that one process ends before it starts again. how is it possible.
void MainWindow::setNewProjectInQueueList()
{
// this is already gotten in queueList now loop thru the list and add project
QStringList arguments;
projNm = ui->lineEditCreateProject->text();
qDebug() << " projNm " << projNm;
for (int j= 0; j < queueList.length(); j++)
{ if (! QString(queueList[j]).isEmpty())
{
// call process
// QString queueName = queueList[j];
arguments << "-sq" << queueList[j];
qDebug() << " arguments sq " << queueList[j];
procQueueList.start("qconf",arguments);
}
}
// and append for each queue with new project name
// and store into the system
}
Brgds,
kNish
Call QProcess::waitForFinished() to wait until the process terminates.
Using the waitForFinished approach from within a loop in the main thread will freeze the application. Instead, putting the loop in a separate thread, or making a queue of processes to start and then launch upon the finished signal from the previous one is good alternatives.

Resources