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, поэтому я в тупике, что мой слот триггера может быть вызван с нулевым объектом таймера!

Из функции установки таймера (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);
    }
}

person RJVB    schedule 10.09.2014    source источник
comment
Может ли это быть из-за того, что я вызываю connect() (потенциально) неоднократно, а не один раз только после new QTimer(0) ?   -  person RJVB    schedule 10.09.2014


Ответы (1)


Должно быть, это действительно так, потому что я выдавал оператор подключения каждый раз, когда сбрасывал таймер, а не только один раз после его создания.

person RJVB    schedule 10.09.2014