QEventLoop in QTimer slot - qt

I have multiple QTimer in the same thread, in the slot connected to the QTimer, I use QEventLoop for synchronization, like http requests, but I found different QTimers may affect each other when they are started in different orders.
Here is my simple test code snippet:
Case 1
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTimer t1;
QTimer t2;
QObject::connect(&t1, &QTimer::timeout, []()->void{
qDebug() << QDateTime::currentDateTimeUtc() << "T1...";
QEventLoop loop;
// t1 slot run time 3000ms
QTimer::singleShot(3000, &loop, SLOT(quit()));
loop.exec();
});
QObject::connect(&t2, &QTimer::timeout, []()->void{
qDebug() << QDateTime::currentDateTimeUtc() << "T2...";
QEventLoop loop;
// t2 slot run time 100ms
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();
});
// interval 1000ms, start t1 first and then t2
t1.start(1000);
t2.start(1000);
return a.exec();
}
Output:
QDateTime(2022-03-21 14:00:51.014 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:00:51.016 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:00:54.025 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:00:54.027 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:00:58.018 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:00:58.019 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:01:01.014 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:01:01.015 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:01:04.016 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:01:04.016 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:01:07.019 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:01:07.020 UTC Qt::TimeSpec(UTC)) T1...
From the output, you can see t2 is affected by t1, the actual interval is about 3000~4000ms, both for t1 and t2, I think t2 should not be affected
Case 2
Just change the QTimer start order, but things will become different
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTimer t1;
QTimer t2;
QObject::connect(&t1, &QTimer::timeout, []()->void{
qDebug() << QDateTime::currentDateTimeUtc() << "T1...";
QEventLoop loop;
// t1 slot run time 3000ms
QTimer::singleShot(3000, &loop, SLOT(quit()));
loop.exec();
});
QObject::connect(&t2, &QTimer::timeout, []()->void{
qDebug() << QDateTime::currentDateTimeUtc() << "T2...";
QEventLoop loop;
// t2 slot run time 100ms
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();
});
// interval 1000ms, start t2 first and then t1
t2.start(1000);
t1.start(1000);
return a.exec();
}
Output:
QDateTime(2022-03-21 14:04:53.653 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:04:53.656 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:54.659 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:55.655 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:56.656 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:04:56.656 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:57.664 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:58.657 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:04:59.665 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:04:59.667 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:00.660 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:01.662 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:02.652 UTC Qt::TimeSpec(UTC)) T2...
QDateTime(2022-03-21 14:05:03.650 UTC Qt::TimeSpec(UTC)) T1...
QDateTime(2022-03-21 14:05:03.653 UTC Qt::TimeSpec(UTC)) T2...
Now t1 does not affect t2 any more, actual interval for t1 is about 3000~4000ms, t2 is 1000ms.
I am really confused why different start order will have different results. Could anyone help me to explain this?
Platform: Qt 5.5.0 MinGW 32bit, Windows
IDE: Qt Creator 3.4.2
You can simply run my test code directly in main() and check the test results.
Thanks.
Edit 1:
I am using QEventLoop for sync http request of RESTFul API, like this:
// m_http is QNetworkAccessManager
QNetworkReply *reply = m_http->get(request);
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
In timer slot, there is only a sync http request, to poll data periodly.
Normally the request will be finished very fast, but sometimes it will cost more than 1000ms if error occurs.
My application need to communicate with multiple server at the same time, and each connection have a timer to do the polling, all connection instances are in the same thread, so all timers share the same eventloop.
My tests is a simple way to simulate the request, using QTimer::singleShot as the time cost by request.
Is there any better way to do sync http request in QT? Using QEventLoop may be not the best.

First, check your QTimer::timerType(): the default is Qt::CoarseTimer, which has a 5% precision. You may need Qt::PreciseTimer instead.
Second, the main Qt event loop will serialize ALL events. Whatever they are. It's an unique pipeline (who can easily become your application's bottleneck, BTW). It also have the bad habit to "pack" some events together (like mouse events) before processing them.
Finally, a QTimer::singleShot is also a real timer, and you launch one inside a slot - which is, basically, executed within event loop context, where you call manually an event loop processing, on two distinct QEventLoop objects...
Honestly, it's not very surprising that your timers do strange things. Could you precise exactly what you need to do with these timers? Because the only thing that your QEventLoop trick do is to block/mess the timer during the requested period, i.e. 3000 ms for T1 and 100 ms for T2, which will obviously mess with the basic 1000 ms period you requested for each...
Normally, you connect the reception signal (finished(QNetworkReply*) for QNetworkAccessManager, but it would be readyRead() for QIODevice) to your slots, and you use sender() to allow a single slot to process various objects simultaneously. You don't synchronize manually anything, you let Qt handles that for you - that's one of the benefits of using a framework. So, the "reply reception" is done this way.
For sending requests, it's up to you. You can use various solutions:
Sending them ASAP once requested (i.e. through a button click).
Buffering them into a FIFO container, using a QTimer to send them without hammering both your machine and the servers. Requests are pushed into the buffer ASAP.
Threading this part - beware, with Qt, you'll need most of the time to call moveToThread() to get this to work properly.
I would prefer the solution #2, with a queue and a specific timer for each targetted server - this will allow a very basic QoS and will avoid that a huge number of requests for one server forbids other servers to be used. You can use, before that, a dispatcher function that would automatically choose the correct queue to use through a map associating a server name (+protocol if needed) and its specific queue and timer.
And when you don't do anything, neither requests (they are all sent) and you're waiting for replies, you let the main Qt event loop do its job: avoiding blocking the message pump - it would produce the "The application is not responding" message. Also, it allows to reduce the CPU load, to get all mouse events for your application, and to refresh GUI elements like a progress bar.

Related

QTime to String with AM/PM and installed translator

This little application make some problems:
int main(int argc, char *argv[])
{
QTranslator* translator = new QTranslator();
QString langCode = "en_GB";
translator->load(QString("Core_%1.qm").arg(langCode));
QCoreApplication::installTranslator(translator);
auto now = QDateTime::currentDateTime();
qDebug() << now.toString(tr("Timeformat"));
return 0
}
For every language I create a separate Core.qm containing a translation for Timeformat. This is for "en_GB"
<message>
<source>Timeformat</source>
<translation>hh:mm ap</translation>
<comment/>
</message>
And this is for "de_DE"
<message>
<source>Timeformat</source>
<translation>hh.mm</translation>
<comment/>
</message>
The system language setting can be different then the loaded language file. If Software is running on a English laptop at 13:57 with loaded Core_de_DE.qm it displays 13.57. ANd with loaded Core_en_GB.qm it show 01:57 pm.
But when the Software running on a french laptop with loaded Core_en_GB.qm (because my Software has no french translation). The Software show 01:57 (the pm is missing). Why?
I've soled this by using the UK Local for every toString call instead of the system one:
//instead of
qDebug() << now.toString(tr("Timeformat"));
// I use now
qDebug() << QLocale("en_GB").toString(now, tr("Timeformat"));

I am getting this watchdog Timer error while doing a simple task in arduino with esp32

i have seen a lot of forums where this problem is dicussed but nothing seems to work. I am working with esp32 and it was all fine untill out of nowhere this watch dog timer error came up. I am new to it so i cant really fix this.
I have another code but i copied a very simple chunk of it and created a new file but watch dog timer error is appearing here too. I dont know what the issue.
it said idle0 is not resetting watach dog timer and "wifi" task is running on cpu0.
ERROR LOG
E (42418) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (42418) task_wdt: - IDLE0 (CPU 0)
E (42418) task_wdt: Tasks currently running:
E (42418) task_wdt: CPU 0: wifi
E (42418) task_wdt: CPU 1: IDLE1
E (42418) task_wdt: Aborting.
abort() was called at PC 0x400d96f7 on core 0
Backtrace: 0x4008c470:0x3ffbe270 0x4008c6a1:0x3ffbe290 0x400d96f7:0x3ffbe2b0 0x400815dd:0x3ffbe2d0 0x40136087:0x00000000
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10088
load:0x40080400,len:6380
entry 0x400806a4
I have tried running my task on cpu1 or core 1 too but wifi is automatically running on cpu or core0. And getting the same error.
have also tried adding delays but nothing works.
char *wssid = "PTCL-TB";
char *wpassword = "pakistan";
bool connected2Wifi = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(10);
Serial.println('\n');
WiFi.begin(wssid, wpassword); // Connect to the network
Serial.print("Connecting to ");
Serial.print(wssid);
while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
delay(500);
Serial.print('.');
}
Serial.println('\n');
Serial.println("Connection established!");
Serial.print("IP address:\t");
Serial.println(WiFi.localIP());
}
void loop() {
// put your main code here, to run repeatedly:
} ```
I want to connect to wifi in this task. It's very simple and i have also copied it from a reliable source whose code was running. but the error seems to be rigid.
Go to Tools -> CPU Frequency and set it to 160, 80 or 240 MHz (the ones that support WiFi/BT).

How to do a non-blocking read on a non-socket fd

Is there a way to do a single read() in non-blocking mode on a pipe/terminal/etc, the way I can do it on a socket with recv(MSG_DONTWAIT)?
The reason I need that is because I cannot find any guarantee that a read() on a file-descriptor returned as ready for reading by select() or poll() will not block.
I know can make the file descriptor non-blocking with fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) but this will change the mode on that file descriptor globally, not just in the calling thread/process. For example:
% perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) | O_NONBLOCK; select undef, undef, undef, undef'
^Z # put it in the background
% cat
cat: -: Resource temporarily unavailable
This will also make the fd non blocking for both reading and writing, which may confuse the hell out of another process doing the opposite on the same fd, as in:
non_blocking_read | filter | blocking_write
One way I think of is to save the file status flags on starting up and SIGCONT, and restore them on exiting and on SIGTSTP (just the way it's done with the termios settings), but this is very limited, race-prone, and will leave a mess behind in the case where the program exited abnormally.
Putting a save/restore with fcntl() before/after each read() also feels ugly and dumb, and may have other issues too. The same with an ioctl(FIONREAD) just before the read (which I'm not even sure it will work reliably with any fd; assurances in that direction will be welcome, though).
I would be happy even with system specific (eg. linux or bsd-only) solutions.
For reference, here is a discussion about fixing it in linux; the idea didn't seem to get anywhere, though.
A Linux only solution would be to reopen the file descriptor via
"/dev/stdin"|"/dev/tty"|"/dev/fd/$fd".
C example:
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd;
char buf[8];
int flags;
if(0>(fd=open("/dev/stdin", O_RDONLY))) return 1;
if(0>(flags = fcntl(fd,F_GETFL))) return 1;
if(0>(flags = fcntl(fd,F_SETFL,flags|O_NONBLOCK))) return 1;
sleep(3);
puts("reading");
ssize_t nr = read(fd, buf, sizeof(buf));
printf("read=%zd\n", nr);
return 0;
}
Unlike a duplicated file descriptor, a reopened filedescriptor will have independent file status flags.

mpiexec checkpointing error (RPi)

When I try to run an application (just a simple hello_world.c doesn't work) I receive this error every time:
mpiexec -ckpointlib blcr -ckpoint-prefix /tmp/ -ckpoint-interval 10 -machinefile /tmp/machinefile -n 1 ./app_name
[proxy:0:0#masterpi] requesting checkpoint
[proxy:0:0#masterpi] checkpoint completed
[proxy:0:0#masterpi] requesting checkpoint
[proxy:0:0#masterpi] HYDT_ckpoint_checkpoint (./tools/ckpoint/ckpoint.c:111): Previous checkpoint has not completed.[proxy:0:0#masterpi] HYD_pmcd_pmip_control_cmd_cb (./pm/pmiserv/pmip_cb.c:905): checkpoint suspend failed
[proxy:0:0#masterpi] HYDT_dmxu_poll_wait_for_event (./tools/demux/demux_poll.c:77): callback returned error status
[proxy:0:0#masterpi] main (./pm/pmiserv/pmip.c:206): demux engine error waiting for event
[mpiexec#masterpi] control_cb (./pm/pmiserv/pmiserv_cb.c:202): assert (!closed) failed
[mpiexec#masterpi] HYDT_dmxu_poll_wait_for_event (./tools/demux/demux_poll.c:77): callback returned error status
[mpiexec#masterpi] HYD_pmci_wait_for_completion (./pm/pmiserv/pmiserv_pmci.c:197): error waiting for event
[mpiexec#masterpi] main (./ui/mpich/mpiexec.c:331): process manager error waiting for completion
I want just to make a checkpoint and nothing else (and restart later).
Thanks in advance
UPDATE:
I have tried with MPICH2, no chance. Or maybe I'm wrong somewhere...
pi#raspberrypi ~ $ mpiexec -n 1 -ckpointlib blcr -ckpoint-prefix /tmp/ -ckpoint-interval 2 ./test3
Count to: 0
[proxy:0:0#raspberrypi] requesting checkpoint
[proxy:0:0#raspberrypi] checkpoint completed
Count to: 1
[proxy:0:0#raspberrypi] requesting checkpoint
[proxy:0:0#raspberrypi] HYDT_ckpoint_checkpoint (/tmp/mpich/mpich2-1.5/src/pm/hydra/tools/ckpoint/ckpoint.c:111): Previous checkpoint has not completed.[proxy:0:0#raspberrypi] HYD_pmcd_pmip_control_cmd_cb (/tmp/mpich/mpich2-1.5/src/pm/hydra/pm/pmiserv/pmip_cb.c:902): checkpoint suspend failed
[proxy:0:0#raspberrypi] HYDT_dmxu_poll_wait_for_event (/tmp/mpich/mpich2-1.5/src/pm/hydra/tools/demux/demux_poll.c:77): callback returned error status
[proxy:0:0#raspberrypi] main (/tmp/mpich/mpich2-1.5/src/pm/hydra/pm/pmiserv/pmip.c:210): demux engine error waiting for event
[mpiexec#raspberrypi] control_cb (/tmp/mpich/mpich2-1.5/src/pm/hydra/pm/pmiserv/pmiserv_cb.c:201): assert (!closed) failed
[mpiexec#raspberrypi] HYDT_dmxu_poll_wait_for_event (/tmp/mpich/mpich2-1.5/src/pm/hydra/tools/demux/demux_poll.c:77): callback returned error status
[mpiexec#raspberrypi] HYD_pmci_wait_for_completion (/tmp/mpich/mpich2-1.5/src/pm/hydra/pm/pmiserv/pmiserv_pmci.c:196): error waiting for event
[mpiexec#raspberrypi] main (/tmp/mpich/mpich2-1.5/src/pm/hydra/ui/mpich/mpiexec.c:325): process manager error waiting for completion
Test3-Code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char* argv[]) {
int rank;
int size;
int i = 0;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Status status;
if (rank == 0) {
for(i; i <=100; i++){
int j = 0;
while(j < 100000000){
j++;
}
printf("Count to: %i\n", i);
}
} else {
}
MPI_Finalize();
return 0;
}
I just need to have one successful checkpoint and to show the restart.
If someone has a working example (irrelevant what it makes, simple working "Hello World" would make me happy!) I would be very glad.
Happy new year!
Unfortunately, the checkpoint/restart code in MPICH 3.0.4 is known to be buggy at the moment. That will hopefully get fixed in a future release. It looks like you're probably using it correctly. It's possible that if you go back to a previous version, you might have better luck.
Here the problem was with the too small interval for checkpointing.
Setting it to 20s or more has solved this (but not the other :( ) problem.

QProcess and shell : Destroyed while process is still running

I want to launch a shell script with Qt.
QProcess process;
process.start(commandLine, QStringList() << confFile);
process.waitForFinished();
if(process.exitCode()!=0)
{
qDebug () << " Error " << process.exitCode() << process.readAllStrandardError();
}
else
{
qDebug () << " Ok " << process.readAllStrandardOutput() << process.readAllStrandardError();
}
The result is :
Ok : Result.... " "" QProcess : Destroyed while process is still
running.
This message does not appear every time.
What is the problem?
process.waitForFinished(); is hitting the default 30 seconds timeout. Use process.waitForFinished(-1); instead. This will make sure you wait for however long it takes for the process to finish, without any timeout.
Note you create QProcess into the local scope. This means that the object will be deleted when you exit the scope. In the destructor QProcess process terminates. The message "Destroyed" while "the process is still running" when the process terminates in the destructor.
For solving this problem, you should call QProcess destructor when process is already terminated.
If will be QProcess::waitForFinished(-1) into your example, it will occur, but this will block you application.

Resources