亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

【Qt源碼筆記】關于 QTimer 在 Windows 下實現的雜談

2023-07-20 07:20:16
45
0

關于 QTimer 的具體實現,翻看源碼源于一次面試經歷。被問到 QTimer 的問題,我隨口說了一句:Windows 平臺下是用 Windows API 實現的,然后便引起了懷疑,不過我據理力爭,便也作罷。所以回來之后,就又確認了一下。

要找這個佐證就必然要從 start( )方法順藤摸瓜。

void QTimer::start()
{
    if (id != INV_TIMER)    // stop running timer
        stop();
    nulltimer = (!inter && single);
    id = QObject::startTimer(inter, Qt::TimerType(type));
}

事實證明還是走到了 QObject 中。繼續順藤摸瓜。

int QObject::startTimer(int interval, Qt::TimerType timerType)
{
    Q_D(QObject);

    if (Q_UNLIKELY(interval < 0)) {
        qWarning("QObject::startTimer: Timers cannot have negative intervals");
        return 0;
    }
    if (Q_UNLIKELY(!d->threadData->hasEventDispatcher())) {
        qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
        return 0;
    }
    if (Q_UNLIKELY(thread() != QThread::currentThread())) {
        qWarning("QObject::startTimer: Timers cannot be started from another thread");
        return 0;
    }
    int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this);
    if (!d->extraData)
        d->extraData = new QObjectPrivate::ExtraData;
    d->extraData->runningTimers.append(timerId);
    return timerId;
}

這里可以很清楚的看到 registerTimer() 方法。不過到這里就可以很快找到方法的位置。 eventDispatcher 讓我直接找到 qeventdispatcher_win.cpp 。果然在這中間,發現了想要找的東西。

void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
{
    Q_ASSERT(internalHwnd);

    Q_Q(QEventDispatcherWin32);

    bool ok = false;
    calculateNextTimeout(t, qt_msectime());
    uint interval = t->interval;
    if (interval == 0u) {
        // optimization for single-shot-zero-timer
        QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
        ok = true;
    } else if (interval < 20u || t->timerType == Qt::PreciseTimer) {
        // 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
        // is still deemed to be the most reliable precision timer.
        t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
                                      TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
        ok = t->fastTimerId;
    }

    if (!ok) {
        // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
        ok = SetTimer(internalHwnd, t->timerId, interval, 0);
    }

    if (!ok)
        qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
}

熟悉的 Windows API 就被發現了。如果當初我能記得 QObject 里邊的調用細節,或許應該就在面試的讓對方少些疑問了。

其實看到這里的邏輯,會發現一些 Qt 的小操作。

  • 一個間隔為 0 的定時器,Qt 只會發一個事件放到事件隊列,不涉及系統 API 調用。
  • 間隔 20ms 以下,會調用 timeSetEvent 。但是這里有兩個隱患:1.  timeSetEvent 是一個已經廢棄的 API;2. timeSetEvent雖然精度高,但是同一個進程開 16 個之后就會失敗,這是一個致命傷,想避開這個問題,就要用最新的 CreateTimerQueueTimer ,由此可見這里是偷懶了。
  • 除此之外的計時器會調用 SetTimer

在這里,會很自然的想到,Timer 的設置是成對出現的,也就是 KillTimer 、 timeKillEvent 這種調用。

通過對 QTimer 機制的理解,不難想到目標代碼應該從 timeEvent 查起。按圖索驥,stop()。最終發現這個:

void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
{
    if (t->interval == 0) {
        QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
    } else if (t->fastTimerId != 0) {
        timeKillEvent(t->fastTimerId);
        QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
    } else if (internalHwnd) {
        KillTimer(internalHwnd, t->timerId);
    }
    t->timerId = -1;
    if (!t->inTimerEvent)
        delete t;
}

Qt 對 Windows API 的基本調用還是可信賴的,但是就是開發人員懶了一點。

0條評論
0 / 1000
Harper
20文章數
0粉絲數
Harper
20 文章 | 0 粉絲
原創

【Qt源碼筆記】關于 QTimer 在 Windows 下實現的雜談

2023-07-20 07:20:16
45
0

關于 QTimer 的具體實現,翻看源碼源于一次面試經歷。被問到 QTimer 的問題,我隨口說了一句:Windows 平臺下是用 Windows API 實現的,然后便引起了懷疑,不過我據理力爭,便也作罷。所以回來之后,就又確認了一下。

要找這個佐證就必然要從 start( )方法順藤摸瓜。

void QTimer::start()
{
    if (id != INV_TIMER)    // stop running timer
        stop();
    nulltimer = (!inter && single);
    id = QObject::startTimer(inter, Qt::TimerType(type));
}

事實證明還是走到了 QObject 中。繼續順藤摸瓜。

int QObject::startTimer(int interval, Qt::TimerType timerType)
{
    Q_D(QObject);

    if (Q_UNLIKELY(interval < 0)) {
        qWarning("QObject::startTimer: Timers cannot have negative intervals");
        return 0;
    }
    if (Q_UNLIKELY(!d->threadData->hasEventDispatcher())) {
        qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
        return 0;
    }
    if (Q_UNLIKELY(thread() != QThread::currentThread())) {
        qWarning("QObject::startTimer: Timers cannot be started from another thread");
        return 0;
    }
    int timerId = d->threadData->eventDispatcher.load()->registerTimer(interval, timerType, this);
    if (!d->extraData)
        d->extraData = new QObjectPrivate::ExtraData;
    d->extraData->runningTimers.append(timerId);
    return timerId;
}

這里可以很清楚的看到 registerTimer() 方法。不過到這里就可以很快找到方法的位置。 eventDispatcher 讓我直接找到 qeventdispatcher_win.cpp 。果然在這中間,發現了想要找的東西。

void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
{
    Q_ASSERT(internalHwnd);

    Q_Q(QEventDispatcherWin32);

    bool ok = false;
    calculateNextTimeout(t, qt_msectime());
    uint interval = t->interval;
    if (interval == 0u) {
        // optimization for single-shot-zero-timer
        QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
        ok = true;
    } else if (interval < 20u || t->timerType == Qt::PreciseTimer) {
        // 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
        // is still deemed to be the most reliable precision timer.
        t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
                                      TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
        ok = t->fastTimerId;
    }

    if (!ok) {
        // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
        ok = SetTimer(internalHwnd, t->timerId, interval, 0);
    }

    if (!ok)
        qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
}

熟悉的 Windows API 就被發現了。如果當初我能記得 QObject 里邊的調用細節,或許應該就在面試的讓對方少些疑問了。

其實看到這里的邏輯,會發現一些 Qt 的小操作。

  • 一個間隔為 0 的定時器,Qt 只會發一個事件放到事件隊列,不涉及系統 API 調用。
  • 間隔 20ms 以下,會調用 timeSetEvent 。但是這里有兩個隱患:1.  timeSetEvent 是一個已經廢棄的 API;2. timeSetEvent雖然精度高,但是同一個進程開 16 個之后就會失敗,這是一個致命傷,想避開這個問題,就要用最新的 CreateTimerQueueTimer ,由此可見這里是偷懶了。
  • 除此之外的計時器會調用 SetTimer

在這里,會很自然的想到,Timer 的設置是成對出現的,也就是 KillTimer 、 timeKillEvent 這種調用。

通過對 QTimer 機制的理解,不難想到目標代碼應該從 timeEvent 查起。按圖索驥,stop()。最終發現這個:

void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
{
    if (t->interval == 0) {
        QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
    } else if (t->fastTimerId != 0) {
        timeKillEvent(t->fastTimerId);
        QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
    } else if (internalHwnd) {
        KillTimer(internalHwnd, t->timerId);
    }
    t->timerId = -1;
    if (!t->inTimerEvent)
        delete t;
}

Qt 對 Windows API 的基本調用還是可信賴的,但是就是開發人員懶了一點。

文章來自個人專欄
文章 | 訂閱
0條評論
0 / 1000
請輸入你的評論
0
0