QTimer: can timer-callback be executed overlapping? - qt

Assumed I have a QTimer which is set up to call its timer-function every 40 msec. Furthermore assumed, the timer-function called by that function needs 200 msec until it returns. So what happens to my timer now (ignoring any jitter and timer-inaccuracies for this example):
is the timer-function called every 40 msecs so that after some time I have 5 overlapping calls of threads being in the same function at the same time?
is the timer called every 200 msec?
is the timer called every 240 msec?
Thank you!

I've simulated your case by a piece of code and result was the third, timer called every 240 ms.
This is the output of my code:
timer callback 1 time QTime("09:44:01.396")
timer callback output 1 time QTime("09:44:01.633")
timer callback 2 time QTime("09:44:01.640")
timer callback output 2 time QTime("09:44:01.875")
timer callback 3 time QTime("09:44:01.875")
timer callback output 3 time QTime("09:44:02.116")
timer callback 4 time QTime("09:44:02.116")
timer callback output 4 time QTime("09:44:02.354")
timer callback 5 time QTime("09:44:02.354")
timer callback output 5 time QTime("09:44:02.585")
P.S:
timer callback 1 time QTime("09:44:01.396")
This line appear when timer timeouts
timer callback output 1 time QTime("09:44:01.633")
And this when the callback function completely done.

Related

Cancel QThread in PyQt5

I have a GUI in PyQt5, which starts a QThread that reads from a serial port. The thread does quit, when it read all the data, but I want to be able to stop it when I click on a stop button. How do I do that? Here is the basic code:
# ...
class Worker(QObject):
finished = pyqtSignal()
progress = pyqtSignal(list)
def __init__(self):
QObject.__init__(self)
self._Reader = Reader()
self._Reader.progress = self.progress
self._Reader.finished = self.finished
def run(self):
self._Reader.read()
class Ui(QtWidgets.QMainWindow):
# ...
def startClicked(self):
self.thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.workerFinished)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.progress.connect(self.reportProgress)
self.thread.start()
def stopClicked(self):
# How do I stop the thread?
pass
when managing threads you can do, as states in the doc here: https://doc.qt.io/qt-5/qthread.html
You can stop the thread by calling exit() or quit().
https://doc.qt.io/qt-5/qthread.html#exit
exit:
Tells the thread's event loop to exit with a return code.
After calling this function, the thread leaves the event loop and returns from the call to QEventLoop::exec(). The QEventLoop::exec() function returns returnCode.
By convention, a returnCode of 0 means success, any non-zero value indicates an error.
https://doc.qt.io/qt-5/qthread.html#quit
quit:
Tells the thread's event loop to exit with return code 0 (success). Equivalent to calling QThread::exit(0).
This function does nothing if the thread does not have an event loop.
I assume that you read data in some data processing loop. If this assumption is wrong, then the following is not valid, of course.
You cannot call secondary thread's quit() directly from the main thread and expect that the secondary thread will process it immediately and quit the thread. The reason is that the thread is busy reading the data in the data processing loop. So you need to break the data processing loop in the secondary thread to make the event loop idle.
(Btw. do not confuse the data processing loop with the event loop. Data processing loop is the one which you have written yourself to read data from the port. The event loop is the loop created by Qt automatically after you called QThread::start() and which is processing events, signals and slots in the secondary thread. This event loop is blocked while your data processing loop is running.)
In order to break the data processing loop, you need to do two things:
call QThread::requestInterruption() from the main thread as response to some "Abort" button having been pressed (do not worry about thread safety, requesting interruption is thread safe/atomic)
within the loop in the secondary thread you need to periodically check QThread::isInterruptionRequested(), and if this returns true, then break the loop and emit worker's finished() signal
Once you broke from the data processing loop in the secondary thread, the event loop in the secondary thread becomes available for processing signals sent from the main thread.
I can see in your code that worker's finished() signal is connected to QThread::quit(). So emitting finished() from the secondary thread (after you broke from the data processing loop) will call thread's quit() which will be processed by the secondary thread's event loop (which is now idle) and it will quit the event loop and subsequently the thread and if you have connected everything correctly it will delete the worker and the thread. (though I have not checked this part of your code)

How Qt Handle Events and Signal in Same EventLoop

I couldn't understand how qt handle events (e.g timer event, socket event etc.) and signals in same event loop.As I understand,timer and socket events are handled via select system call(in Unix like OS).
How an event loop handle signals while sleeping because of select system call.
In Qt, signals are used to call slots. When you emit a signal, there are, roughly speaking, only 2 options for calling the corresponding slot:
Direct slot call. This can be thought of as replacing a line with a signal emitting by a line with just a slot call. An event loop is not used to process this signal itself.
Delayed slot call. In this case, the signal will be converted to an event, and the event will be posted to the receiver event loop (the event enqueues in the event loop of the thread the receiver object is living in). From now on, for the processing receiver event loop, it makes no difference whether it was a signal or an event. The event will be picked up by the event loop and will cause the slot invocation sometime later.
From Qt doc: https://doc.qt.io/qt-5/signalsandslots.html#signals
When a signal is emitted, the slots connected to it are usually
executed immediately, just like a normal function call. When this
happens, the signals and slots mechanism is totally independent of any
GUI event loop. Execution of the code following the emit statement
will occur once all slots have returned. The situation is slightly
different when using queued connections; in such a case, the code
following the emit keyword will continue immediately, and the slots
will be executed later.
As for understanding an event loop, an event loop is just a loop which process one event from an event queue on each iteration.
In short, this can be represented as follows:
QQueue<QEvent> eventQueue; // Events (and pending slot calls as well) are added to this queue
...
// How an event loop works (schematically):
while(event = eventQueue.dequeue())
{
do_what_the_event_wants_or_ignore_it(event);
}
Read also https://wiki.qt.io/Threads_Events_QObjects

when the event loop starts in Dart and how the event queue works

The first question is when the event loop starts ?
I read in a site that it's start after the main method
but why when we try something like this
main()async {
Future(()=>print('future1'));
await Future(()=>print('future2'));
print('end of main');
}
//the output is :
//future1
//future2
//end of main
in this example the event loop start when we use the await keyword and
after the event loop reaches the future2 it's paused ?
or i am wrong :(
The second question is how the events is added to event queue
if it's FIFO why in this example the future 2 is completed before
future 1
main(){
Future.delayed(Duration(seconds:5) , ()=>print('future1'));
Future.delayed(Duration(seconds:2) , ()=>print('future2'));
}
The event loop run when there is nothing else running (e.g. main method is done, you are waiting for some future to complete).
Your example makes sense because the first line puts an event on event queue so now the first item in the queue is "print('future1')". In the next line, you are putting another event on the queue which calls "print('future2')" and now you await for this event to be done.
Since your main method is not waiting for something then the event loop is going to be executed. Since the first event on the queue was "print('future1')" then this is going to be executed first. But since the main method is still waiting for the future "print('future2')" to be complete then the event loop takes another event to be executed which are going to be "print('future2')".
Since this event was the one the main method was waiting for (and there is no more event on the event queue) then main() are going to run the last call "print('end of main')".
In your next example, you think that Future and Future.delayed are the same which it is not. With Future.delayed there are not going any event in the event queue before. Instead, there are running a thread outside the VM which knows when the next timer should trigger which ends up putting an event on the queue. So the event is only being put on the event queue when the timer has been expired (and therefore, the future2 are going to be executed first).

Adobe AIR issue

I have an Adobe AIR application with a chart component displaying some online data.
The chart component has to display a bunch of parameters about 10 of them.
The application has a timer to display current system time.
The chart component is invoked from the timer(using a bindable object) as shown below. A separate bindable object is used to prevent delay in timer.
private function onTimerEvent(event:TimerEvent):void
{
//Update time in screen
oCurrDate = new Date();
curTime = oDateformatter.format(oCurrDate).toString();
oCurrDate = null;
//oUpdate- Bindable object to inform chart about update
//Call chart every 250 ms
oUpdate.bUpdate = !oUpdate.bUpdate;
}
Iam using a calllater function in chart's update event as shown below. updateParameter() will update the dataprovider of each of the parameter and draws it.
public function onUpdateEvent(evt:PropertyChangeEvent):void
{
//aPlotIndex set to 0 for first parameter
aPlotIndex.push(0);
this.callLater(updateParameter, aPlotIndex);
}
The problem is the timer and chart updation stops after running 20 to 21 days. After 20 or 21 days, the update happens only on mouse move. When I moved mouse the time displayed & data in chart are updated.
I profiled the application and found that there is no memory leakage issues. I am logging all the errors but I didn't get any error in the log also. Everything seems weird.
Is it because of using the calllater function.
Is it that the timer is still running but frame update not happening.
I am using Flex SDK3.3 and Flex AIR version 2.0.4.13090.
Please guide me to resolve this issue.
Please read the documentation for Timer.
The total number of times the timer is set to run. If the repeat count is set to 0, the timer continues indefinitely, up to a maximum of 24.86 days, or until the stop() method is invoked or the program stops. If the repeat count is nonzero, the timer runs the specified number of times. If repeatCount is set to a total that is the same or less then currentCount the timer stops and will not fire again.
The maximum is due to the max of an int, which is what the timer uses to store its current count. int has a max value of 2,147,483,647. 2147483647 / 24.86 days / 1440 minutes / 60 seconds /1000 milliseconds is equal to 1 (give or take, differences with the way the docs' number is rounded), which aligns with the fact that the internal clock stores its count per millisecond the Timer has run.
So you cannot set an option to fix this. Instead, you can work around it, assuming nothing actually relies on your timer's value. Each time the timer runs, call
timer.reset();
timer.start();
That will reset the timer to 0 and start it back up again, meaning you will never hit that 24.86 day limit, unless your delay is longer than that (which it cannot possibly be)
Additionally, I'd like to point out that the Flex and AIR versions you are running are severely out of date. Both are nearly 5 years old at this point. AIR may not even run properly on newer versions of Windows and OS X because of it (and won't run on mobile at all). Not a big deal if everything works, but always good to know (many posters on SO do not realize how out of date their Flex and AIR SDKs are)
Timer.repeatCount
int.MAX_VALUE

how to make a process on the server check an entry in a database x seconds after it has been inserted

I have an application where orders are sent to be processed by waiters. However, a waiter has 30 seconds to confirm that he accepts the order, or it will be passed to the next. How can I check if the IsAccepted column in the orders table was marked as true 30 seconds after the entry was inserted?
I'm looking for a solution as easy as possible. Thank you
Simplest thing is to start a timer to fire 30 seconds after the insert.
See Comparing the Timer Classes in the .NET Framework Class Library on MSDN for a comparison of the different timer classes.
Just make sure to stop the timer in the tick event handler (or Elapsed handler or whatever handler corresponds to the timer you select).

Resources