国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
驅(qū)動(dòng)編程基礎(chǔ)教程第五章:時(shí)間與定時(shí)器 - Aliwy編程空間[http://www.ntd...
第五章 時(shí)間與定時(shí)器
5.1 獲得當(dāng)前滴答數(shù)
在編程中,獲得當(dāng)前的系統(tǒng)日期和時(shí)間,或者是獲得一個(gè)從啟動(dòng)開始的毫秒數(shù),是很常見的需求。獲得系統(tǒng)日期和時(shí)間往往是為了寫日志。獲得啟動(dòng)毫秒數(shù)很適合用來做一個(gè)隨機(jī)數(shù)的種子。有時(shí)也使用時(shí)間相關(guān)的函數(shù)來尋找程序的性能瓶頸。
熟悉Win32應(yīng)用程序開發(fā)的讀者會(huì)知道有一個(gè)函數(shù)GetTickCount(),這個(gè)函數(shù)返回系統(tǒng)自啟動(dòng)之后經(jīng)歷的毫秒數(shù)。在驅(qū)動(dòng)開發(fā)中有一個(gè)對(duì)應(yīng)的函數(shù)KeQueryTickCount(),這個(gè)函數(shù)的原型如下:
VOID 
KeQueryTickCount(
  OUT PLARGE_INTEGER  TickCount
);
遺憾的是,被返回到TickCount中的并不是一個(gè)簡單的毫秒數(shù)。這是一個(gè)“滴答”數(shù)。但是一個(gè)“滴答”到底為多長的時(shí)間,在不同的硬件環(huán)境下可能有所不同。為此,必須結(jié)合另一個(gè)函數(shù)使用。下面這個(gè)函數(shù)獲得一個(gè)“滴答”的具體的100納秒數(shù)。
ULONG 
  KeQueryTimeIncrement(
  );
得知以上的關(guān)系之后,下面的代碼可以求得實(shí)際的毫秒數(shù):
void MyGetTickCount (PULONG msec)
{
  LARGE_INTEGER tick_count;
  ULONG myinc = KeQueryTimeIncrement();
  KeQueryTickCount(&tick_count);
  tick_count.QuadPart *= myinc;
  tick_count.QuadPart /=  10000;
  *msec = tick_count.LowPart;
}
這不是一個(gè)簡單的過程。不過所幸的是,現(xiàn)在有代碼可以拷貝了。
5.2 獲得當(dāng)前系統(tǒng)時(shí)間
接下來的一個(gè)需求是得到當(dāng)前的可以供人類理解的時(shí)間。包括年、月、日、時(shí)、分、秒這些要素。在驅(qū)動(dòng)中不能使用諸如CTime之類的MFC類。不過與之對(duì)應(yīng)的有TIME_FIELDS,這個(gè)結(jié)構(gòu)中含有對(duì)應(yīng)的時(shí)間要素。
KeQuerySystemTime()得到當(dāng)前時(shí)間。但是得到的并不是當(dāng)?shù)貢r(shí)間,而是一個(gè)格林威治時(shí)間。之后請(qǐng)使用ExSystemTimeToLocalTime()轉(zhuǎn)換可以當(dāng)?shù)貢r(shí)間。這兩個(gè)函數(shù)的原型如下:
VOID 
KeQuerySystemTime(
OUT PLARGE_INTEGER  CurrentTime
);
VOID
ExSystemTimeToLocalTime(
IN PLARGE_INTEGER  SystemTime,
OUT PLARGE_INTEGER  LocalTime
);
這兩個(gè)函數(shù)使用的“時(shí)間”都是長長整型數(shù)據(jù)結(jié)構(gòu)。這不是人類可以閱讀的。必須通過函數(shù)RtlTimeToTimeFields轉(zhuǎn)換為TIME_FIELDS。這個(gè)函數(shù)原型如下:
VOID 
RtlTimeToTimeFields(
IN PLARGE_INTEGER  Time,
IN PTIME_FIELDS  TimeFields
);
讀者需要實(shí)際應(yīng)用一下來加深印象。下面寫出一個(gè)函數(shù):這個(gè)函數(shù)返回一個(gè)字符串。這個(gè)字符串寫出當(dāng)前的年、月、日、時(shí)、分、秒,這些數(shù)字之間用“-”號(hào)隔開。這是一個(gè)很有用的函數(shù)。而且同時(shí)用到上面三個(gè)函數(shù),此外,請(qǐng)讀者回憶前面關(guān)于字符串的打印的相關(guān)章節(jié)。
PWCHAR MyCurTimeStr()
{
  LARGE_INTEGER snow,now;
  TIME_FIELDS now_fields;
  static WCHAR time_str[32] = { 0 };
  // 獲得標(biāo)準(zhǔn)時(shí)間
  KeQuerySystemTime(&snow);
  // 轉(zhuǎn)換為當(dāng)?shù)貢r(shí)間
  ExSystemTimeToLocalTime(&snow,&now);
  // 轉(zhuǎn)換為人類可以理解的時(shí)間要素
  RtlTimeToTimeFields(&now,&now_fields);
  // 打印到字符串中
  RtlStringCchPrintfW(
  time_str,
  32*2,
  L"%4d-%2d-%2d %2d-%2d-%2d",
  now_fields.Year,now_fields.Month,now_fields.Day,
  now_fields.Hour,now_fields.Minute,now_fields.Second);
  return time_str;
}
請(qǐng)注意time_str是靜態(tài)變量。這使得這個(gè)函數(shù)不具備多線程安全性。請(qǐng)讀者考慮一下,如何保證多個(gè)線程同時(shí)調(diào)用這個(gè)函數(shù)的時(shí)候,不出現(xiàn)沖突?
5.3 使用定時(shí)器
使用過Windows應(yīng)用程序編程的讀者的讀者一定對(duì)SetTimer()映像尤深。當(dāng)需要定時(shí)執(zhí)行任務(wù)的時(shí)候,SetTimer()變得非常重要。這個(gè)功能在驅(qū)動(dòng)開發(fā)中可以通過一些不同的替代方法來實(shí)現(xiàn)。比較經(jīng)典的對(duì)應(yīng)是KeSetTimer(),這個(gè)函數(shù)的原型如下:
BOOLEAN
KeSetTimer(
  IN PKTIMER  Timer,        // 定時(shí)器
  IN LARGE_INTEGER  DueTime,// 延后執(zhí)行的時(shí)間
  IN PKDPC  Dpc  OPTIONAL   // 要執(zhí)行的回調(diào)函數(shù)結(jié)構(gòu)
);
其中的定時(shí)器Timer和要執(zhí)行的回調(diào)函數(shù)結(jié)構(gòu)Dpc都必須先初始化。其中Timer的初始化比較簡單。下面的代碼可以初始化一個(gè)Timer:
KTIMER my_timer;
KeInitializeTimer(&my_timer);
Dpc的初始化比較麻煩。這是因?yàn)樾枰峁┮粋€(gè)回調(diào)函數(shù)。初始化Dpc的函數(shù)原型如下:
VOID
KeInitializeDpc(
  IN PRKDPC  Dpc,
  IN PKDEFERRED_ROUTINE  DeferredRoutine,
  IN PVOID  DeferredContext
);
PKDEFERRED_ROUTINE這個(gè)函數(shù)指針類型所對(duì)應(yīng)的函數(shù)的類型實(shí)際上是這樣的:
VOID
CustomDpc(
  IN struct _KDPC  *Dpc,
  IN PVOID  DeferredContext,
  IN PVOID  SystemArgument1,
  IN PVOID  SystemArgument2
);
讀者需要關(guān)心的只是DeferredContext。這個(gè)參數(shù)是KeInitializeDpc調(diào)用時(shí)傳入的參數(shù)。用來提供給CustomDpc被調(diào)用的時(shí)候,讓用戶傳入一些參數(shù)。
至于后面的SystemArgument1和SystemArgument2則請(qǐng)不要理會(huì)。Dpc是回調(diào)這個(gè)函數(shù)的KDPC結(jié)構(gòu)。
請(qǐng)注意這是一個(gè)“延時(shí)執(zhí)行”的過程。而不是一個(gè)定時(shí)執(zhí)行的過程。因此每次執(zhí)行了之后,下次就不會(huì)再被調(diào)用了。如果想要定時(shí)反復(fù)執(zhí)行,就必須在每次CustomDpc函數(shù)被調(diào)用的時(shí)候,再次調(diào)用KeSetTimer,來保證下次還可以執(zhí)行。
值得注意的是,CustomDpc將運(yùn)行在APC中斷級(jí)。因此并不是所有的事情都可以做(在調(diào)用任何內(nèi)核系統(tǒng)函數(shù)的時(shí)候,請(qǐng)注意WDK說明文檔中標(biāo)明的中斷級(jí)要求。)
這些事情非常的煩惱,因此要完全實(shí)現(xiàn)定時(shí)器的功能,需要自己封裝一些東西。下面的結(jié)構(gòu)封裝了全部需要的信息:
// 內(nèi)部時(shí)鐘結(jié)構(gòu)
typedef struct MY_TIMER_
{
  KDPC dpc;
  KTIMER timer;
  PKDEFERRED_ROUTINE func;
  PVOID private_context;
} MY_TIMER,*PMY_TIMER;
// 初始化這個(gè)結(jié)構(gòu):
void MyTimerInit(PMY_TIMER timer, PKDEFERRED_ROUTINE func)
{
  // 請(qǐng)注意,我把回調(diào)函數(shù)的上下文參數(shù)設(shè)置為timer,為什么要
  // 這樣做呢?
  KeInitializeDpc(&timer->dpc,sf_my_dpc_routine,timer);
  timer->func = func;
  KeInitializeTimer(&timer->timer);
  return (wd_timer_h)timer;
}
// 讓這個(gè)結(jié)構(gòu)中的回調(diào)函數(shù)在n毫秒之后開始運(yùn)行:
BOOLEAN MyTimerSet(PMY_TIMER timer,ULONG msec,PVOID context)
{
  LARGE_INTEGER due;
  // 注意時(shí)間單位的轉(zhuǎn)換。這里msec是毫秒。
  due.QuadPart = -10000*msec;
  // 用戶私有上下文。
  timer->private_context = context;
  return KeSetTimer(&timer->timer,due,&mytimer->dpc);
};
  
// 停止執(zhí)行
VOID MyTimerDestroy(PMY_TIMER timer)
{
  KeCancelTimer(&mytimer->timer);
};
使用結(jié)構(gòu)PMY_TIMER已經(jīng)比結(jié)合使用KDPC和KTIMER簡便許多。但是還是有一些要注意的地方。真正的OnTimer回調(diào)函數(shù)中,要獲得上下文,必須要從timer->private_context中獲得。此外,OnTimer中還有必要再次調(diào)用MyTimerSet(),來保證下次依然得到執(zhí)行。
VOID
MyOnTimer (
  IN struct _KDPC  *Dpc,
  IN PVOID  DeferredContext,
  IN PVOID  SystemArgument1,
  IN PVOID  SystemArgument2
)
{
  // 這里傳入的上下文是timer結(jié)構(gòu),用來下次再啟動(dòng)延時(shí)調(diào)用
  PMY_TIMER timer = (PMY_TIMER)DeferredContext;
  // 獲得用戶上下文
  PVOID my_context = timer->private_context;
  // 在這里做OnTimer中要做的事情
  ……
  // 再次調(diào)用。這里假設(shè)每1秒執(zhí)行一次
  MyTimerSet(timer,1000,my_context);
};
關(guān)于定時(shí)器就介紹到這里了。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
驅(qū)動(dòng)程序中文件,定時(shí)器,IO
函數(shù)防抖
linux 內(nèi)核定時(shí)器解析
Qt中定時(shí)器使用的兩種方法
【IOS基礎(chǔ)知識(shí)】NSTimer定時(shí)器使用
Windows精準(zhǔn)計(jì)時(shí)&精準(zhǔn)Timer
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服