Qt 為何沒有提供 Sleep
論壇上不時見到有人問:
- Qt 為什么沒有提供跨平台的 sleep 函數?
- 使用平台相關的 Sleep 或 nanosleep 以后,界面為什么沒有反應?
- QThread 中提供了protected 權限的 sleep 函數,如何用到主線程中?
- 使用 QTest 中的 qSleep,在windows下如何隱藏控制台?
這些問題其實歸結為一點:在主線程中使用這些函數是一種錯誤,這會直接導致界面無法刷新,用戶與程序無法交互。
Qt不提供,是因為你不需要在主線程中使用 sleep 函數。
如何讓程序等待一段時間
QTime
QTime t; t.start(); while(t.elapsed()<1000);
這種死循環也是一種常見錯誤用法。但改成正確的還是比較簡單的:
QTime t; t.start(); while(t.elapsed()<1000) QCoreApplication::processEvents();
不停地處理事件,以使得程序保持響應。
QElapsedTimer
這是Qt4.7引入的新的類,和QTime相比,它提供了更快的計算 elapsed 時間的方法。
QElapsedTimer t; t.start(); while(t.elapsed()<1000) QCoreApplication::processEvents();
QTest::qWait
這是QTest模塊提供的等待函數
下面是其源代碼(和我們前面的代碼很像吧?):
namespace QTest { inline static void qWait(int ms) { Q_ASSERT(QCoreApplication::instance()); QElapsedTimer timer; timer.start(); do { QCoreApplication::processEvents(QEventLoop::AllEvents, ms); QTest::qSleep(10); } while (timer.elapsed() < ms); } ...
其實沒什么魔力,對吧?但是因為它QTest模塊,所以在程序中我們不要使用它。
QEventLoop
配合QTimer使用局部的 eventLoop 也是一個不錯的選擇。例子:
QEventLoop eventloop; QTimer::singleShot(100, &eventloop, SLOT(quit())); eventloop.exec();
QTimer 和 QBasicTimer
這兩個和本文沒有什么直接關系,QTimer估計大家都很熟了。而QBasicTimer估計很少有人用。
- 與QTimer相比,QBasicTimer更快速、輕量、底層。
- 與QTimer相比,它不是QObject的派生類。
跨平台的sleep
盡管一開始我們就說了,不需要這個東西。但不排除某種場合下,你確實需要這個東西。如何實現一個跨平台的 sleep 呢?
我們一開始也提到了,QThread類 和 QTest模塊都提供了sleep函數,其實我們只需要看看他們的源碼就夠了:
QTest 模塊中的函數很簡單(windows下調用Sleep,其他平台調用 nanosleep):
void QTest::qSleep(int ms) { QTEST_ASSERT(ms > 0); #ifdef Q_OS_WIN Sleep(uint(ms)); #else struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; nanosleep(&ts, NULL); #endif }
看QThread的源碼,windows下同樣直接調用Sleep,但非windows的實現比這個就復雜多了:
- static void thread_sleep(struct timespec *ti)
- {
- pthread_mutex_t mtx;
- pthread_cond_t cnd;
- pthread_mutex_init(&mtx, 0);
- pthread_cond_init(&cnd, 0);
- pthread_mutex_lock(&mtx);
- (void) pthread_cond_timedwait(&cnd, &mtx, ti);
- pthread_mutex_unlock(&mtx);
- pthread_cond_destroy(&cnd);
- pthread_mutex_destroy(&mtx);
- }
- void QThread::sleep(unsigned long secs)
- Qt 為何沒有提供 Sleep
- 論壇上不時見到有人問:
- Qt 為什么沒有提供跨平台的 sleep 函數?
- 使用平台相關的 Sleep 或 nanosleep 以后,界面為什么沒有反應?
- QThread 中提供了protected 權限的 sleep 函數,如何用到主線程中?
- 使用 QTest 中的 qSleep,在windows下如何隱藏控制台?
- 這些問題其實歸結為一點:在主線程中使用這些函數是一種錯誤,這會直接導致界面無法刷新,用戶與程序無法交互。
- Qt不提供,是因為你不需要在主線程中使用 sleep 函數。
- 如何讓程序等待一段時間
- QTime
- QTime t;
- t.start();
- while(t.elapsed()<1000);
- 這種死循環也是一種常見錯誤用法。但改成正確的還是比較簡單的:
- QTime t;
- t.start();
- while(t.elapsed()<1000)
- QCoreApplication::processEvents();
- 不停地處理事件,以使得程序保持響應。
- QElapsedTimer
- 這是Qt4.7引入的新的類,和QTime相比,它提供了更快的計算 elapsed 時間的方法。
- QElapsedTimer t;
- t.start();
- while(t.elapsed()<1000)
- QCoreApplication::processEvents();
- QTest::qWait
- 這是QTest模塊提供的等待函數
- 下面是其源代碼(和我們前面的代碼很像吧?):
- namespace QTest
- {
- inline static void qWait(int ms)
- {
- Q_ASSERT(QCoreApplication::instance());
- QElapsedTimer timer;
- timer.start();
- do {
- QCoreApplication::processEvents(QEventLoop::AllEvents, ms);
- QTest::qSleep(10);
- } while (timer.elapsed() < ms);
- }
- ...
- 其實沒什么魔力,對吧?但是因為它QTest模塊,所以在程序中我們不要使用它。
- QEventLoop
- 配合QTimer使用局部的 eventLoop 也是一個不錯的選擇。例子:
- QEventLoop eventloop;
- QTimer::singleShot(100, &eventloop, SLOT(quit()));
- eventloop.exec();
- QTimer 和 QBasicTimer
- 這兩個和本文沒有什么直接關系,QTimer估計大家都很熟了。而QBasicTimer估計很少有人用。
- 與QTimer相比,QBasicTimer更快速、輕量、底層。
- 與QTimer相比,它不是QObject的派生類。
- 跨平台的sleep
- 盡管一開始我們就說了,不需要這個東西。但不排除某種場合下,你確實需要這個東西。如何實現一個跨平台的 sleep 呢?
- 我們一開始也提到了,QThread類 和 QTest模塊都提供了sleep函數,其實我們只需要看看他們的源碼就夠了:
- QTest 模塊中的函數很簡單(windows下調用Sleep,其他平台調用 nanosleep):
- void QTest::qSleep(int ms)
- {
- QTEST_ASSERT(ms > 0);
- #ifdef Q_OS_WIN
- Sleep(uint(ms));
- #else
- struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
- nanosleep(&ts, NULL);
- #endif
- }
- 看QThread的源碼,windows下同樣直接調用Sleep,但非windows的實現比這個就復雜多了:
- view plaincopy to clipboardprint?
- static void thread_sleep(struct timespec *ti)
- {
- pthread_mutex_t mtx;
- pthread_cond_t cnd;
- pthread_mutex_init(&mtx, 0);
- pthread_cond_init(&cnd, 0);
- pthread_mutex_lock(&mtx);
- (void) pthread_cond_timedwait(&cnd, &mtx, ti);
- pthread_mutex_unlock(&mtx);
- pthread_cond_destroy(&cnd);
- pthread_mutex_destroy(&mtx);
- }
- void QThread::sleep(unsigned long secs)
- {
- struct timeval tv;
- gettimeofday(&tv, 0);
- struct timespec ti;
- ti.tv_sec = tv.tv_sec + secs;
- ti.tv_nsec = (tv.tv_usec * 1000);
- thread_sleep(&ti);
- }
- {
- struct timeval tv;
- gettimeofday(&tv, 0);
- struct timespec ti;
- ti.tv_sec = tv.tv_sec + secs;
- ti.tv_nsec = (tv.tv_usec * 1000);
- thread_sleep(&ti);
- }
方法一:
class SleeperThread : public QThread
{
public:
static void msleep(unsigned long msecs)
{
QThread::msleep(msecs);
}
};// 調用方法
SleeperThread::msleep(1000);
方法二:
QMutex mutex;
QWaitCondition sleep;
mutex.lock();
sleep.wait(&mutex, 1000);
mutex.unlock();