從這一篇開(kāi)始,我們介紹那些QF系統(tǒng)框架提供給我們的服務(wù),QF這里稱(chēng)為一個(gè)系統(tǒng)框架,其實(shí)你可以理解為它為了適配狀態(tài)機(jī)而提供的一些必要服務(wù),針對(duì)操作系統(tǒng)進(jìn)行也一些裁剪,時(shí)間管理這個(gè)概念在操作系統(tǒng)中應(yīng)用的更加廣泛,例如任務(wù)時(shí)間片分配,任務(wù)睡眠,喚醒這些都是基于強(qiáng)大的時(shí)間管理,系統(tǒng)心跳為這一切提供強(qiáng)大的支持,在QF中時(shí)間管理的一大核心任務(wù)就是為【定時(shí)事件】服務(wù)。
因?yàn)榛谑录?qū)動(dòng)型系統(tǒng)的核心之一就是【事件】,事件又被分為了兩種,一種為普通事件、一種叫做定時(shí)事件。普通事件相對(duì)來(lái)講比較簡(jiǎn)單,它所處理的事件都是實(shí)時(shí)的(換句話(huà)說(shuō)隨時(shí)可能發(fā)生),而還有一種情況需要在給定的時(shí)間發(fā)送事件,這種叫做定時(shí)事件。
定時(shí)事件 = 普通事件 + 鬧鐘(定時(shí)機(jī)制)。
用一張結(jié)構(gòu)定義圖來(lái)分析他們之間的關(guān)系,如下:
這里我們不再講普通事件涉及的內(nèi)容,雖然簡(jiǎn)單,留到后面講事件隊(duì)列的時(shí)候一起講比較合適,不管普通事件還是定時(shí)事件,本質(zhì)都是事件,對(duì)于狀態(tài)機(jī)而言,他們都需要事件隊(duì)列的支持。這里我會(huì)站在應(yīng)用的角度上來(lái)分析一下定時(shí)功能,當(dāng)然也會(huì)涉及一部分底層的實(shí)現(xiàn),但是盡量不講,學(xué)習(xí)的時(shí)候一定要分清自己的目的,你是想要學(xué)會(huì)如何應(yīng)用QF系統(tǒng)框架,還是重寫(xiě)一個(gè)系統(tǒng)框架,扯遠(yuǎn)了。。。
要應(yīng)用事件的定時(shí)功能,主要涉及框架提供的幾個(gè)接口操作:
1. postIn()提供單次定時(shí)功能。
2. postEvery()提供周期性定時(shí)功能。
3. disarm()提供相應(yīng)定時(shí)功能的解除。
關(guān)于定時(shí)功能的理解,其實(shí)有個(gè)很簡(jiǎn)單的方式,掏出你的手機(jī),打開(kāi)你的鬧鐘,設(shè)定一個(gè)鬧鐘,設(shè)置過(guò)程他會(huì)提示你 僅響鈴一次,還是循環(huán)定時(shí),同樣在你設(shè)定了鬧鐘以后,在定時(shí)事件沒(méi)到之前,你可以隨時(shí)取消鬧鐘,就是我們的disarm(),這里都是介紹的這幾個(gè)功能原型,真正的API可能并不是這樣,也有可能被定義成了一個(gè)宏。
系統(tǒng)心跳systemtick,這個(gè)詞我相信你在操作系統(tǒng)領(lǐng)域聽(tīng)得耳朵都有點(diǎn)長(zhǎng)繭子了,要實(shí)現(xiàn)上面的定時(shí)功能, 需要設(shè)置一個(gè)系統(tǒng)心跳,系統(tǒng)時(shí)鐘街拍是一個(gè)以預(yù)先確定的速率發(fā)生的周期性中斷(這里指的是硬件中斷,后面會(huì)介紹一種新的軟中斷),典型的速率在10到100hz之間,實(shí)際的頻率取決你的應(yīng)用所需的最小時(shí)基,節(jié)拍的速率并不是越快越好,越快代表著更多的時(shí)間管理開(kāi)銷(xiāo)(管理開(kāi)銷(xiāo)會(huì)導(dǎo)致你的定時(shí)時(shí)間的誤差,主頻更快的CPU可以消解這種誤差的大小,但是我們的CPU受制于成本不可能無(wú)限的快)。
時(shí)間事件在應(yīng)用時(shí)需要注意以下幾點(diǎn):
1. 時(shí)間事件必須是靜態(tài)的,不能是動(dòng)態(tài)的(事件從定義的方式來(lái)講可以分為靜態(tài)和動(dòng)態(tài)兩種),這里遵守就好了。
2. 一個(gè)時(shí)間事件在實(shí)例化時(shí),必須分配一個(gè)信號(hào),并且這個(gè)信號(hào)不能被改變。
下面以QPC6.9.1版本源碼為基礎(chǔ),以dpp為例從真實(shí)的角度來(lái)介紹一下其應(yīng)用,首先看一下時(shí)間事件的定義及接口函數(shù),以一個(gè)應(yīng)用為例講一下如何應(yīng)用事件事件服務(wù)于我們的狀態(tài)機(jī),先看一下定義:
接口函數(shù)部分是重點(diǎn),因?yàn)檎嬲趹?yīng)用程序中需要應(yīng)用他們,如下:
針對(duì)這些常用的API函數(shù),我們需要詳細(xì)了解他們的參數(shù)才能更好的使用他們,如下:
還剩下兩個(gè)不怎么常用的函數(shù),就不介紹了,等你用到的時(shí)候可以自己去翻看一下源碼,QP一個(gè)很強(qiáng)的設(shè)定是不怎么需要API參考手冊(cè),因?yàn)榫瓦@清晰的注釋可以幫你看透一切。
如何在實(shí)際中去使用定時(shí)事件才是我們最終的目的,關(guān)于使用我們以dpp為例,分了幾個(gè)步驟來(lái)使用,如下:
【第一步】定義事件對(duì)象結(jié)構(gòu)并實(shí)例化它。
【第二步】 在活動(dòng)對(duì)象構(gòu)造時(shí),調(diào)用相應(yīng)的定時(shí)事件構(gòu)造函數(shù)。
【第三步】在狀態(tài)處理過(guò)程中,啟動(dòng)定時(shí)器(最常用的方式)。
總結(jié)一下,在實(shí)際應(yīng)用時(shí),需要特別注意兩個(gè)點(diǎn),應(yīng)用環(huán)境(位置)和調(diào)用參數(shù)設(shè)定。整個(gè)QF定時(shí)事件的功能,都是依賴(lài)于QF_tick,在這里并沒(méi)有講如何設(shè)置該函數(shù),因?yàn)樗c移植有關(guān)。
到這里關(guān)于QF時(shí)間管理之定時(shí)事件的應(yīng)用就分析完了。