1.å¦ä½è®© Qt çç¨åºä½¿ç¨ Sleep
2.easylogging源码学习笔记(6)
3.å¦ä½è®© Qt ç¨åº Sleep
4.do_gettimeofday与ktime_get_real_ts64
å¦ä½è®© Qt çç¨åºä½¿ç¨ Sleep
Qt 为ä½æ²¡ææä¾ Sleep
论åä¸ä¸æ¶è§å°æ人é®ï¼
Qt 为ä»ä¹æ²¡ææä¾è·¨å¹³å°ç sleep å½æ°ï¼
使ç¨å¹³å°ç¸å ³ç Sleep æ nanosleep 以åï¼çé¢ä¸ºä»ä¹æ²¡æååºï¼
QThread ä¸æä¾äºprotected æéç sleep å½æ°ï¼å¦ä½ç¨å°ä¸»çº¿ç¨ä¸ï¼
ä½¿ç¨ QTest ä¸ç qSleepï¼å¨windowsä¸å¦ä½éèæ§å¶å°ï¼
è¿äºé®é¢å ¶å®å½ç»ä¸ºä¸ç¹ï¼å¨ä¸»çº¿ç¨ä¸ä½¿ç¨è¿äºå½æ°æ¯ä¸ç§é误ï¼è¿ä¼ç´æ¥å¯¼è´çé¢æ æ³å·æ°ï¼ç¨æ·ä¸ç¨åºæ æ³äº¤äºã
Qtä¸æä¾ï¼æ¯å ä¸ºä½ ä¸éè¦å¨ä¸»çº¿ç¨ä¸ä½¿ç¨ sleep å½æ°ã
å¦ä½è®©ç¨åºçå¾ ä¸æ®µæ¶é´
QTime
QTime t;
t.start();
while(t.elapsed()<);
è¿ç§æ»å¾ªç¯ä¹æ¯ä¸ç§å¸¸è§é误ç¨æ³ãä½æ¹ææ£ç¡®çè¿æ¯æ¯è¾ç®åçï¼
QTime t;
t.start();
while(t.elapsed()<)
QCoreApplication::processEvents();
ä¸åå°å¤çäºä»¶ï¼ä»¥ä½¿å¾ç¨åºä¿æååºã
QElapsedTimer
è¿æ¯Qt4.7å¼å ¥çæ°çç±»ï¼åQTimeç¸æ¯ï¼å®æä¾äºæ´å¿«çè®¡ç® elapsed æ¶é´çæ¹æ³ã
QElapsedTimer t;
t.start();
while(t.elapsed()<)
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();
} while (timer.elapsed() < ms);
}
...
å ¶å®æ²¡ä»ä¹éå,对å§ï¼ä½æ¯å 为å®QTest模åï¼æ以å¨ç¨åºä¸æ们ä¸è¦ä½¿ç¨å®ã
QEventLoop
é åQTimer使ç¨å±é¨ç eventLoop ä¹æ¯ä¸ä¸ªä¸éçéæ©ãä¾åï¼
QEventLoop eventloop;
QTimer::singleShot(, &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 / , (ms % ) * * };
nanosleep(&ts, NULL);
#endif
}
çQThreadçæºç ï¼windowsä¸åæ ·ç´æ¥è°ç¨Sleepï¼ä½éwindowsçå®ç°æ¯è¿ä¸ªå°±å¤æå¤äºï¼
[cpp] view plain copy
/* /internal
helper function to do thread sleeps, since usleep()/nanosleep()
aren't reliable enough (in terms of behavior and availability)
*/
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 * );
thread_sleep(&ti);
}
easylogging源码学习笔记(6)
`LOG` 是默认日志、CLOG自定义日志、源码LOG_IF条件日志
特殊日志
LOG_EVERY_N、源码LOG_AFTER_N、源码网站织梦源码LOG_N_TIMES
for (int i = 1; i <= ; ++i) {
LOG_EVERY_N(2,源码 INFO) << "Logged every second iter";
}// 5 logs written; 2, 4, 6, 7,
for (int i = 1; i <= ; ++i) {
LOG_AFTER_N(2, INFO) << "Log after 2 hits; " << i;
}// 8 logs written; 3, 4, 5, 6, 7, 8, 9,
for (int i = 1; i <= ; ++i) {
LOG_N_TIMES(3, INFO) << "Log only 3 times; " << i;
}// 3 logs writter; 1, 2, 3
条件日志和特殊日志可以搭配使用
* `VLOG_IF(condition, verbose-level)`
* `CVLOG_IF(condition, verbose-level, loggerID)`
* `VLOG_EVERY_N(n, verbose-level)`
* `CVLOG_EVERY_N(n, verbose-level, loggerID)`
* `VLOG_AFTER_N(n, verbose-level)`
* `CVLOG_AFTER_N(n, verbose-level, loggerID)`
* `VLOG_N_TIMES(n, verbose-level)`
* `CVLOG_N_TIMES(n, verbose-level, loggerID)`
日志详细等级判定
if (VLOG_IS_ON(2)) {
// Verbosity level 2 is on for this file
}
性能追踪
* `TIMED_FUNC(obj-name)`
* `TIMED_SCOPE(obj-name, block-name)`
* `TIMED_BLOCK(obj-name, block-name)`
这些宏实际上都是关于el::base::type::PerformanceTrackerPtr,一个指向el::base::PerformanceTracker的源码指针
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
PerformanceTracker::PerformanceTracker(const std::string& blockName,
base::TimestampUnit timestampUnit,
const std::string& loggerId,
bool scopedLog, Level level) :
m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog),
m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) {
#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
// We store it locally so that if user happen to change configuration by the end of scope
// or before calling checkpoint, we still depend on state of configuration at time of construction
el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level);
if (m_enabled) {
base::utils::DateTime::gettimeofday(&m_startTime);
}
#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
}
在构造函数中获取一个时间,
PerformanceTracker::~PerformanceTracker(void) {
#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
if (m_enabled) {
base::threading::ScopedLock scopedLock(lock());
if (m_scopedLog) {
base::utils::DateTime::gettimeofday(&m_endTime);
base::type::string_t formattedTime = getFormattedTimeTaken();
PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
data.init(this);
data.m_formattedTimeTaken = formattedTime;
PerformanceTrackingCallback* callback = nullptr;
for (const std::pair& h
: ELPP->m_performanceTrackingCallbacks) {
callback = h.second.get();
if (callback != nullptr && callback->enabled()) {
callback->handle(&data);
}
}
}
}
#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
}
在析构函数中获取一个时间,源码处理时间data,源码使用PerformanceTrackingCallback类型指针callback,源码并在callback->handle(&data)中处理输出。源码
由于定义了ELPP_FEATURE_PERFORMANCE_TRACKING,源码大趋势指标源码因此在初始化(INITIALIZE_EASYLOGGINGPP)中实际上是源码安装了一个base::DefaultPerformanceTrackingCallback。
在PerformanceTracker类的源码handle函数中,callback是源码一个PerformanceTrackingCallback类型指针,由于安装的源码是DefaultPerformanceTrackingCallback对象,因此是皮肤源码怎么用一个基类指针指向了派生类对象。处理输出的逻辑在DefaultPerformanceTrackingCallback类的handle函数中。
DefaultPerformanceTrackingCallback类的handle函数首先会将数据成员m_data的指针赋值给函数参数,并创建一个base::type::stringstream_t类型的对象ss用于构建输出内容。根据m_data的dataType,输出不同的歪歪pc协议源码信息。在输出时,会使用el::base::Writer类构造并输出内容。
å¦ä½è®© Qt ç¨åº Sleep
使ç¨å¹³å°ç¸å ³ç Sleep æ nanosleep 以åï¼çé¢ä¸ºä»ä¹æ²¡æååºï¼QThread ä¸æä¾äºprotected æéç sleep å½æ°ï¼å¦ä½ç¨å°ä¸»çº¿ç¨ä¸ï¼ä½¿ç¨QTest ä¸ç qSleepï¼å¨windowsä¸å¦ä½éèæ§å¶å°ï¼è¿äºé®é¢å ¶å®å½ç»ä¸ºä¸ç¹ï¼å¨ä¸»çº¿ç¨ä¸ä½¿ç¨è¿äºå½æ°æ¯ä¸ç§é误ï¼è¿ä¼ç´æ¥å¯¼è´çé¢æ æ³å·æ°ï¼ç¨æ·ä¸ç¨åºæ æ³äº¤äºãQtä¸æä¾ï¼æ¯å ä¸ºä½ ä¸éè¦å¨ä¸»çº¿ç¨ä¸ä½¿ç¨ sleep å½æ°ãå¦ä½è®©ç¨åºçå¾ ä¸æ®µæ¶é´QTimeQTime t; t.start(); while(t.elapsed()<);è¿ç§æ»å¾ªç¯ä¹æ¯ä¸ç§å¸¸è§é误ç¨æ³ãä½æ¹ææ£ç¡®çè¿æ¯æ¯è¾ç®åçï¼QTime t; t.start(); while(t.elapsed()<) QCoreApplication::processEvents();ä¸åå°å¤çäºä»¶ï¼ä»¥ä½¿å¾ç¨åºä¿æååºãQElapsedTimerè¿æ¯Qt4.7å¼å ¥çæ°çç±»ï¼åQTimeç¸æ¯ï¼å®æä¾äºæ´å¿«çè®¡ç® elapsed æ¶é´çæ¹æ³ãQElapsedTimer t; t.start(); while(t.elapsed()<) 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(); } while (timer.elapsed() < ms); } ...å ¶å®æ²¡ä»ä¹éå,对å§ï¼ä½æ¯å 为å®QTest模åï¼æ以å¨ç¨åºä¸æ们ä¸è¦ä½¿ç¨å®ãQEventLoopé åQTimer使ç¨å±é¨ç eventLoop ä¹æ¯ä¸ä¸ªä¸éçéæ©ãä¾åï¼ QEventLoop eventloop; QTimer::singleShot(, &eventloop, SLOT(quit())); eventloop.exec();QTimer å QBasicTimerè¿ä¸¤ä¸ªåæ¬æ没æä»ä¹ç´æ¥å ³ç³»ï¼QTimer估计大家é½å¾çäºãèQBasicTimer估计å¾å°æ人ç¨ãä¸QTimerç¸æ¯ï¼QBasicTimeræ´å¿«éãè½»éãåºå±ãä¸QTimerç¸æ¯ï¼å®ä¸æ¯QObjectçæ´¾çç±»ã跨平å°çsleep尽管ä¸å¼å§æ们就说äºï¼ä¸éè¦è¿ä¸ªä¸è¥¿ãä½ä¸æé¤æç§åºåä¸ï¼ä½ ç¡®å®éè¦è¿ä¸ªä¸è¥¿ã橹械æ®��èè»ã£â³indowsä¸è°ç¨Sleepï¼å ¶ä»å¹³å°è°ç¨ nanosleepï¼ï¼void QTest::qSleep(int ms) { QTEST_ASSERT(ms > 0); #ifdef Q_OS_WIN Sleep(uint(ms)); #else struct timespec ts = { ms / , (ms % ) * * }; nanosleep(&ts, NULL); #endif }çQThreadçæºç ï¼windowsä¸åæ ·ç´æ¥è°ç¨Sleepï¼ä½éwindowsçå®ç°æ¯è¿ä¸ªå°±å¤æå¤äºï¼/* \internal helper function to do thread sleeps, since usleep()/nanosleep() aren't reliable enough (in terms of behavior and availability)*/staticvoidthread_sleep(structtimespec *ti){ pthread_mutex_tmtx;pthread_cond_tcnd;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);}voidQThread::sleep(unsignedlongsecs){ structtimevaltv;gettimeofday(&tv, 0);structtimespecti;ti.tv_sec = tv.tv_sec + secs;ti.tv_nsec = (tv.tv_usec * );thread_sleep(&ti);}
do_gettimeofday与ktime_get_real_ts
do_gettimeofday函数,自linux v0..9版本诞生,起初为内部inline static函数。小甲鱼汇编源码至linux v2.0版本,正式升级为外部接口。其定义位于arch/i/kernel/time.c。然而,随着linux v5.0的更新,do_gettimeofday退出历史舞台。原因在于struct timeval在bit机器上面临问题。替代函数为ktime_get_real_ts。这一替代被官方文档明确指出,详细信息可参考"linux kernel documentation"中的"ktme accessors"部分。对于问题的深入探讨,推荐阅读"静海听风:什么是年问题"。
ktime_get_real_ts于linux v3.版本面世,最初以宏定义形式存在。在linux v5.0版本中,随着do_gettimeofday的退役,ktime_get_real_ts正式登场。其定义位于kernel/time/timekeeping.c,声明则在include/linux/timekeeping.h。具体实现和使用详情,需查阅相关源代码和文档。