I have implemented an idle timer on a resource (class) instances of which can be open in several applications at once. Hence, the idleTimer is not only a simple QTimer, but the slot (trigger) needs to verify if no other applications have accessed the same resources during the last N minutes. If that is the case, the timer is reset (without updating the lastAccessedTime value), otherwise the resource is closed. The timer is thus a singleshot one, and lastAccessTime is kept in a QSharedMemory object.
Here's some trace output:
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83601 timer QTimer(0x11d273d60) triggered 1 times
### slotIdleTimedOut ->handleIdleTiming: setting QTimer(0x11d273d60) for wallet "kdewallet" handle 0 timeout to 6
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83634 timer QTimer(0x11d273d60) triggered 2 times
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83634 timer QTimer(0x11d273d60) triggered 3 times
### "Google Contacts ()of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83634 timer QTimer(0x11d273d60) triggered 4 times
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83634 timer QTimer(0x11d273d60) triggered 5 times
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83635 timer QTimer(0x11d273d60) triggered 6 times
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83635 timer QTimer(0x11d273d60) triggered 7 times
### "Google Contacts () of type Google Contacts" Idle timeout 6 min. for KWallet::Wallet(0x105d1f900) "kdewallet" handle 0 ; elapsed minutes= 5.83635 timer QTimer(0x11d273d60) triggered 8 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle 0 ; elapsed minutes= 6 timer QTimer(0x120a1b5f0) triggered 1 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00008 timer QObject(0x0) triggered 2 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00009 timer QObject(0x0) triggered 3 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00012 timer QObject(0x0) triggered 4 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00012 timer QObject(0x0) triggered 5 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00012 timer QObject(0x0) triggered 6 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00012 timer QObject(0x0) triggered 7 times
### "KMail" Idle timeout 6 min. for KWallet::Wallet(0x1083f1ac0) "kdewallet" handle -1 ; elapsed minutes= 6.00012 timer QObject(0x0) triggered 8 times
The principle works, but I notice 2 things:
the timer fires a bit early. Of course that causes the timer to be reset.
it fires several times in fast succession. The fact that an early fire should reset it doesn't have the slightest effect.
Below is the relevant part of my code, including the function that resets the timer at each resource access, and the timer's trigger slot.
Any idea what I'm doing wrong? I stop the timer before (re)setting it to singleshot mode and starting it (anew). The object and application identifiers show that it is indeed the same timer that triggers multiple times, and that it can get triggered even after I deleted the timer object.
Could it be that the trigger slot is not application (or even instance) specific, somehow leading to 1 instance receiving the idleTimer trigger signals from all other instances across the various applications that set an instance of this timer? idleTimer gets set to NULL only in the class destructor and/or when timeOut is <=0, so I'm stymied that my trigger slot can get called with a NULL timer object!
From the timer install function (handleIdleTiming, a member of KWallet::Wallet as is the idleTimer itself):
// This function is to be called at every operation that is supposed to launch or reset
// the idle timing. #p timeOut is a time in minutes.
void handleIdleTiming(const char *caller="", bool touchAccessTime=true)
{
// ...
if( timeOut >= 0 ){
if( !idleTimer ){
idleTimer = new QTimer(0);
}
else{
idleTimer->stop();
}
// when the idle timer fires, the wallet is supposed to be closed. There is thus
// no reason to use a repeating timer.
idleTimer->setSingleShot(true);
connect( idleTimer, SIGNAL(timeout()), q, SLOT(slotIdleTimedOut()) );
if( touchAccessTime ){
if( lastAccessTime.lock() ){
*((double*)lastAccessTime.data()) = HRTime_Time();
lastAccessTime.unlock();
}
else{
qDebug() << "Cannot lock lastAccessTime for wallet" << name << "error" << lastAccessTime.errorString();
}
}
idleTimer->start( timeOut * 60 * 1000 );
The timer trigger slot:
void Wallet::slotIdleTimedOut()
{ double lastAccessTime = 0;
// check the last time anyone accessed this wallet:
if( d->lastAccessTime.lock() ){
lastAccessTime = *((double*)d->lastAccessTime.data());
d->lastAccessTime.unlock();
}
else{
qDebug() << "Cannot lock lastAccessTime for wallet" << d->name << "error" << d->lastAccessTime.errorString();
}
// the time elapsed since that last access, in minutes:
double elapsed = (HRTime_Time() - lastAccessTime) / 60;
d->idleTimerTriggered += 1;
qDebug() << "###" << appid() << "Idle timeout" << d->timeOut << "min. for" << this << d->name << "handle" << d->handle
<< "; elapsed minutes=" << elapsed << "timer" << d->idleTimer << "triggered" << d->idleTimerTriggered << "times";
if( elapsed >= d->timeOut ){
// we have a true timeout, i.e. we didn't access the wallet in timeOut minutes, and no one else did either.
slotWalletClosed(d->handle);
}
else{
// false alarm, reset the timer, but there's no need to count this as an access!
d->handleIdleTiming(__FUNCTION__, false);
}
}
Must indeed have been because I issued a connect statement each time I reset the timer, instead of only once after creating it.
Related
I follow the reference document on Coroutine (https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html) and I test in the same time the example on Android Studio (a good boy).
But I am very confuse with cancelAndJoin() method.
If I replace, in the example code, the "cancelAndJoin" with "join", there is no difference in logs.
Here is the code :
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // computation loop, just wastes CPU
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
}
and in the 2 cases (with join or cancelAndJoin) the logs are :
job: I'm sleeping 0 ...
job: I'm sleeping 1 ...
job: I'm sleeping 2 ...
main: I'm tired of waiting!
job: I'm sleeping 3 ...
job: I'm sleeping 4 ...
main: Now I can quit.
Does anybody can explain what is the difference with the 2 methods?
This is not clear because cancel is "stopping the job", join is "waiting for completion", but the two together??? We "stop" and "wait"???
Thanks by advance :)
This is not clear because cancel is "stopping the job", join is
"waiting for completion", but the two together??? We "stop" and
"wait"?
Just because we wrote job.cancel() doesn't mean that job will cancel immediately.
When we write job.cancel() the job enters a transient cancelling state. This job is yet to enter the final cancelled state and only after the job enters the cancelled state it can be considered completely cancelled.
Observe how the state transition occurs,
When we call job.cancel() the cancellation procedure(transition from completing to cancelling) starts for the job. But we still need to wait, as the job is truly cancelled only when it reaches the cancelled state. Hence we write job.cancelAndJoin(), where cancel() starts the cancellation procedure for job and join() makes sure to wait until the job() has reached the cancelled state.
Make sure to check out this excellent article
Note: The image is shamelessly copied from the linked article itself
Ok I've just realize that my question was stupid!
cancelAndJoin() is equal to do cancel() and then join().
The code demonstrate that the job can not be cancelled if we don't check if it is active or not. And to do so, we must use "isActive".
So like this:
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (isActive) { // cancellable computation loop
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
libuv has a central event loop and allows asynchronous network I/O, timers etc around it.
The high level architecutre as presented in the docs is:
When the event loop blocks for "ready" sockets (using epoll etc), how does it unblock itself if none of the sockets are ready? It might miss some timers which could run out in the meantime.
If it immediately unblocks if none of the sockets are empty, and there are no timers to trigger, doesn't the event loop degenerate to "busy waiting" for sockets to get ready?
uv_run makes sure to not busy wait by passing an additional timeout parameter to the polling function. On windows the implementation to calculate the timeout for the polling call basically looks like this
int uv__next_timeout(const uv_loop_t* loop) {
const struct heap_node* heap_node;
const uv_timer_t* handle;
uint64_t diff;
/* If not timer block indefinitely */
heap_node = heap_min(timer_heap(loop));
if (heap_node == NULL)
return -1;
/* Timer should have fired already */
handle = container_of(heap_node, uv_timer_t, heap_node);
if (handle->timeout <= loop->time)
return 0;
/* Timer fires in the future, compute the timeout until the
next timer should fire */
diff = handle->timeout - loop->time;
if (diff > INT_MAX)
diff = INT_MAX;
return (int) diff;
}
Only if no timers are available the loop will block until a socket / IO completion port is ready to be consumed, otherwise it will block for at most the time until the next timeout should fire. The heap_min makes sure to always return the next timer to not miss any.
I would like to use an arduino to read 433 MHz transmission from multiple Soil Moisture Sensors. Since I can never be sure all transmissions reach the receiver I'd like to set a countdown from the moment the first transmission is received. If another transmission is received, the countdown starts again.
After a defined amount of time (e.g. 10 Minutes) without any more signals or if all signals have been received (e.g 4 Sensors) the receiving unit should stop and come to decision based on the data it got to the point.
For transmitting and receiving I am using the <RCSwitch.h>library.
The loop of the receiving unit and one Sensor looks like this:
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void Setup(){
Serial.begin(9600);
mySwitch.enableReceive(4);
}
void loop() {
if (mySwitch.available()) {
int value = mySwitch.getReceivedValue();
if (value == 0) {
lcd.clear();
Serial.print("Unknown encoding");
}
else {
Serial.print(mySwitch.getReceivedValue());
Serial.print("%");
}
The full code includes some differentiation mechanism for all sensors but I figured that might not be relevant for my question.
Question:
What's the best way to do this without a real time clock module. As far as I know I can't wait by using delay(...)since then I won't receive any data while the processor waiting.
You can use millis() as a clock. It returns the number of milliseconds since the arduino started.
#define MINUTES(x) ((x) * 60000UL)
unsigned long countStart = 0;
void loop()
{
if (/*read from module ok*/)
{
countStart = millis();
// sanity check, since millis() eventually rolls over
if (countStart == 0)
countStart = 1;
}
if (countStart && ((millis() - countStart) > MINUTES(10)))
{
countStart = 0;
// trigger event
}
}
Arduino's internal timers can also be used in this situation. If a long time period is needed, it's better to use 16bit counter (usually timer1) at 1024 prescaler (largest available). If the largest time interval of timer is greater than time required, then a counter have to be added in order to keep track of 1 minute interval.
For example, for 1-minute interval, initialize registers as:
TCCR1A = 0; //Initially setting every register as 0x0000
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 468750; // compare match register 16MHz/1024/2/frequency(hz)
TCCR1B |= (1 << WGM12); // Timer compare mode
TCCR1B |= (1 << CS10) | (1 << CS10); // 1024 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
These configuration of timer will give interrupt time of 1 minute. And upon timer completion ISR TIMER1_COMPA_vect will be run. You can play around with value of OCR1A for different interrupt periods.
Main advantage of using interrupts is that they don't block any task and can will be executed instantaneously (if interrupts are not disabled explicitly).
I need to wait for a period of time while checking whether a button is pressed (so whether an input is HIGH or LOW).
The delay function is annoying to use for this because it cannot check whether something is happening while being delayed, so it would have to wait for 1 ms, check, wait, check, wait, check etc...
Can you help me with the coding I would need to check and pause for a set amount of time, at the same time?
You can realize that with a second condition-controlled loop.
If you want to wait in each arduino main loop as an example for 20 seconds and execute in this time span further code you can do this as follows:
unsigned long startTime = millis(); // Number of milliseconds since the program started (unsigned long)
unsigned long intervalTime = 20000UL; // equals 20 seconds
int buttonPin = 3; // used button pin
void loop()
{
while(millis() - startTime < intervalTime){
if(digitalRead(buttonPin)==HIGH){
//...
}
else {
//...
}
}
//...
}
I've been using Xcode to implement a timer and run calculations off the time. However every so often the timer will skip an interation, which throws off all the calculations.
- (void)Time
{
if (running==false) return;
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval elapsed = currentTime - startTime;
int mins = (int) (elapsed / 60.0);
elapsed -= mins* 60;
int seconds = (int) (elapsed);
elapsed -= seconds;
int fraction = elapsed * 100.0;
beepTime = [self Dec:seconds+elapsed];
[self mod];
label.text= [NSString stringWithFormat:#"%u:%02u.%.01u",mins,seconds,fraction/10];
[self performSelector:#selector(Time) withObject:nil afterDelay:0.01];
}
Here is a small sample of some logs
2012-08-14 20:25:04.659 RT 8.470000 BP 50.710000 MT 8.360000
2012-08-14 20:25:04.671 RT 8.470000 BP 50.720000 MT 8.370000
2012-08-14 20:25:04.682 RT 8.470000 BP 50.740000 MT 8.390000
note that BP 50.730000 and MT 8.380000 have been skipped.
Any suggestions?
Cheers!
If you read the documentation on -performSelector:withObject:afterDelay: it makes no guarantees that the message is sent exactly after 0.01 seconds delay. Instead it says that the message is put to event queue after 0.01 seconds and fired whenever it is its turn.
You might be better off by using NSTimer's method + scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:.
Eventhough timer works also in the current run loop similarly than performSelector, atleast it wouldn't execute in 0.01 + (time it took to execute -Time method body).
Note that you need to call that NSTimer method only once and use its returned value to invalidate the timer.