Singleshot QTimer на OS X быстро срабатывает несколько раз и слишком рано
Я реализовал таймер простоя на ресурсе (классе), экземпляры которого могут быть открыты в нескольких приложениях одновременно. Следовательно idleTimer
это не просто QTimer
, но слот (триггер) должен проверить, если другие приложения не обращались к тем же ресурсам в течение последних N минут. Если это так, таймер сбрасывается (без обновления lastAccessedTime
значение), в противном случае ресурс закрыт. Таймер, таким образом, одиночный, и lastAccessTime
хранится в объекте QSharedMemory.
Вот некоторые результаты трассировки:
### "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
Принцип работает, но я замечаю 2 вещи:
- Таймер срабатывает немного раньше. Конечно, это приводит к сбросу таймера.
- он стреляет несколько раз подряд. Тот факт, что ранний пожар должен сбросить его, не имеет ни малейшего эффекта.
Ниже приведена соответствующая часть моего кода, включая функцию, которая сбрасывает таймер при каждом доступе к ресурсу, и триггерный интервал таймера.
Есть идеи, что я делаю не так? Я останавливаю таймер перед тем, как (пере) установить его в режим одиночной съемки и запустить его (заново). Идентификаторы объекта и приложения показывают, что это действительно один и тот же таймер, который срабатывает несколько раз, и что он может срабатывать даже после того, как я удалил объект таймера.
Может быть, слот триггера не зависит от приложения (или даже экземпляра), что как-то приводит к тому, что 1 экземпляр получает idleTimer
запускать сигналы от всех других экземпляров в различных приложениях, которые устанавливают экземпляр этого таймера? idleTimer
получает значение NULL только в деструкторе класса и / или когда timeOut
равен <=0, поэтому я зашел в тупик, так как мой триггерный слот может быть вызван с объектом NULL timer!
Из функции установки таймера (handleIdleTiming
, член KWallet::Wallet
как это idleTimer
сам):
// 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 );
Слот запуска по таймеру:
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);
}
}
1 ответ
Должно быть так, потому что я выполнял оператор подключения каждый раз, когда сбрасывал таймер, а не только один раз после его создания.