傅瑤,韓誠(chéng)山
多媒體定時(shí)器方法中MFC跨線程傳遞窗口類(lèi)消息的實(shí)現(xiàn)
傅瑤,韓誠(chéng)山
為實(shí)現(xiàn)高頻數(shù)據(jù)采集,采用多媒體定時(shí)器的方法實(shí)現(xiàn)上位機(jī)精確定時(shí),同時(shí)研究實(shí)現(xiàn)了MFC中跨線程窗口類(lèi)消息傳遞問(wèn)題的解決方案。實(shí)驗(yàn)表明,定時(shí)精度高,達(dá)到10毫秒精確定時(shí),不會(huì)出現(xiàn)數(shù)據(jù)丟失,運(yùn)行良好。
多媒體定時(shí)器;跨線程;窗口類(lèi)消息傳遞
Windows系統(tǒng)中實(shí)現(xiàn)定時(shí)功能有多種方式,但多數(shù)無(wú)法實(shí)現(xiàn)精確定時(shí)。例如,使用sleep函數(shù)實(shí)現(xiàn)延時(shí),最小計(jì)時(shí)精度僅為30毫秒,而且只能用于延時(shí)精度要求不高的程序中;使用Timer組件定時(shí)。首先,調(diào)用SetTimer函數(shù)創(chuàng)建一個(gè)定時(shí)器,然后,以一定的時(shí)間間隔向 Windows發(fā)送一個(gè)WM_TIMER消息,操作系統(tǒng)捕獲此消息后處理相應(yīng)事件。但是,由于這種方式定時(shí)中斷的響應(yīng)頻率是每秒 18.2次,對(duì)小于55毫秒的事件計(jì)時(shí)器就會(huì)丟消息。因此,該方法只適用于對(duì)時(shí)間要求并不嚴(yán)格的場(chǎng)合;VC中也可以使用GetTickCount函數(shù)實(shí)現(xiàn)延時(shí)或定時(shí),該方法使用時(shí)CPU占用率較低,因此,運(yùn)行期間也能處理其他消息,但降低了定時(shí)精度。
多媒體定時(shí)器是一類(lèi)高精度定時(shí)器。使用多媒體定時(shí)器不易丟失消息,特別是其觸發(fā)的最小時(shí)間間隔在10毫秒左右,精度較以上定時(shí)方法提高很多。
當(dāng)然,Windows下還有更高精度的定時(shí)器,比如使用VC 提供的供 Windows系統(tǒng)使用的精確時(shí)間函數(shù)QueryPerformanceFrequency和 QueryPerformanceCounter,這兩個(gè)函數(shù)要求計(jì)算機(jī)從硬件上支持精確定時(shí)器,精度與CPU等機(jī)器配置有關(guān),實(shí)現(xiàn)較復(fù)雜。
本文定時(shí)的應(yīng)用是基于光柵尺測(cè)量位移數(shù)據(jù)量的采集。由于位移量的振動(dòng)頻率最高可達(dá)到 60Hz,即周期要求小于16.7ms,因此時(shí)間間隔設(shè)置為10ms才能夠滿(mǎn)足要求;又考慮在Windows這樣的多任務(wù)操作系統(tǒng)下即使定時(shí)器精度設(shè)置過(guò)高,也有可能被更高優(yōu)先級(jí)的任務(wù)掛起,考慮到這一點(diǎn),尤其是每隔10ms就要采集一次數(shù)據(jù),任務(wù)繁重,因此綜合考慮,采用多媒體定時(shí)器的定時(shí)方法。
綜合分析以上因素,本文采用多媒體定時(shí)器的方法實(shí)現(xiàn)了毫秒級(jí)的精確定時(shí),其中難點(diǎn)是窗口類(lèi)跨線程的使用。
Windows多媒體定時(shí)器可以使用TimeSetEvent函數(shù)建立定時(shí)器事件,在回調(diào)函數(shù)中觸發(fā)事件消息[1][2][4]。多媒體定時(shí)器在自身線程中運(yùn)行,當(dāng)定時(shí)器事件被觸發(fā)時(shí),其自身線程會(huì)即刻停止工作,轉(zhuǎn)而調(diào)用回調(diào)函數(shù),執(zhí)行回調(diào)函數(shù)中需要周期性執(zhí)行的任務(wù),而暫時(shí)中止自身線程,因此,該方法定時(shí)精度高。
timeSetEvent函數(shù)觸發(fā)一個(gè)指定的定時(shí)器事件。多媒體定時(shí)器在自有的線程里運(yùn)行。事件被觸發(fā)后,它調(diào)用指定的回調(diào)函數(shù)或設(shè)置指定的事件對(duì)象。
語(yǔ)法如下

各參數(shù)的意義及設(shè)置如下,m_CurTimerRes = 10,初始多媒體定時(shí)間隔 10ms,以毫秒指定事件周期;m_wAccuracy 以毫秒指定延時(shí)精度,默認(rèn)值為 1毫秒;m_pCallBackProc = NULL,即為回調(diào)函數(shù)指針;m_dwUser= dwUser ,為回調(diào)函數(shù)傳入?yún)?shù),用于存放用戶(hù)提供的回調(diào)數(shù)據(jù);fuEvent 取值為1或0,指定定時(shí)器事件類(lèi)型,如果設(shè)置為T(mén)IME_ONESHOT ,則m_CurTimerRes后只產(chǎn)生一次事件;如果設(shè)置為 TIME_PERIODIC,則每隔m_CurTimerRes毫秒周期性地產(chǎn)生事件。
在調(diào)用timeSetEvent函數(shù)時(shí),將需要周期性執(zhí)行的語(yǔ)句(如:定時(shí)采樣、控制等)定義在 lpFunction回調(diào)函數(shù)中,從而完成需要定時(shí)處理的事件。在定時(shí)器使用結(jié)束后,再及時(shí)調(diào)用timeKillEvent釋放資源。通過(guò)timeSetEvent函數(shù)和timeKillEvent函數(shù)啟動(dòng)和停止一個(gè)定時(shí)器,精度可以達(dá)到1毫秒,滿(mǎn)足系統(tǒng)應(yīng)用要求。
然而timeSetEvent函數(shù)需要周期調(diào)用回調(diào)函數(shù),在本任務(wù)處理的事件中某些語(yǔ)句如CWnd,CDC類(lèi)的對(duì)象無(wú)法直接通過(guò)回調(diào)函數(shù)使用,也就是說(shuō)窗口類(lèi) CWnd類(lèi)的內(nèi)容在線程中不能直接傳遞。
MFC窗口類(lèi)無(wú)法跨線程直接使用。原因是,原則上MFC對(duì)象語(yǔ)句只能被創(chuàng)建該對(duì)象的線程訪問(wèn),而無(wú)法被其他線程訪問(wèn)。而本文的系統(tǒng)運(yùn)行中,在位移數(shù)據(jù)量采集時(shí)需要同步繪圖。繪圖中要使用的 CWnd、CDC這些類(lèi)及其派生類(lèi)產(chǎn)生的對(duì)象,只能由生成該對(duì)象的線程訪問(wèn),別的線程不能訪問(wèn)。這是因?yàn)?GDI對(duì)象是一種全局資源,如果對(duì)其進(jìn)行并發(fā)控制,常常容易出錯(cuò),所以微軟在設(shè)計(jì) MFC時(shí),C++對(duì)象和線程局部存儲(chǔ)中的一個(gè)結(jié)構(gòu)是捆綁起來(lái)的[3][4],如果跨線程使用和窗口有關(guān)的函數(shù),程序就會(huì)運(yùn)行失敗。因此窗口類(lèi)在多線程環(huán)境下使用時(shí),所有對(duì)窗口語(yǔ)句的操作都應(yīng)該在創(chuàng)建該窗口的線程中執(zhí)行,不能直接跨線程使用。
解決跨線程訪問(wèn)MFC窗口對(duì)象的方法主要有兩個(gè)。一種方法是在接收窗口句柄的線程中用 FromHandle 創(chuàng)建一個(gè)新的窗口對(duì)象并將其加入maps中。首先,將各個(gè)句柄(如HWND)而不是 C++ 對(duì)象傳遞到輔助線程。然后,輔助線程調(diào)用適當(dāng)?shù)?FromHandle 成員函數(shù)把這些對(duì)象添加到它的臨時(shí)映射。此外,還可以通過(guò)調(diào)用 Attach 將對(duì)象添加到線程的永久映射。但這種操作只有在對(duì)象比線程存在的時(shí)間長(zhǎng)時(shí)才應(yīng)當(dāng)進(jìn)行[5]。
另一種方法是僅傳遞窗口句柄而不直接傳遞窗口類(lèi)對(duì)象。這種方法首先需要?jiǎng)?chuàng)建新的用戶(hù)定義消息,該消息與輔助線程將要執(zhí)行的不同任務(wù)相對(duì)應(yīng)。然后使用::PostMessage函數(shù)將這些消息發(fā)布到應(yīng)用程序的主窗口[5]。這種通訊方式類(lèi)似于兩個(gè)不同的應(yīng)用程序在對(duì)話(huà),而這兩個(gè)線程是在同一地址空間中執(zhí)行的。
具體來(lái)說(shuō),通過(guò)傳遞句柄實(shí)現(xiàn)窗口對(duì)象的跨線程訪問(wèn),可以在窗口映射一個(gè)消息,比如ON_MESSAGE(WM_ONDRAW, CWINDOW),然后在所用線程中發(fā)送postmessage消息給窗口,窗口的消息處理肯定是在線程里面,這時(shí)可以實(shí)現(xiàn)窗口類(lèi)消息的傳遞了。
本文采用傳遞窗口句柄的方式實(shí)現(xiàn)MFC窗口對(duì)象的跨線程訪問(wèn)。在另外一個(gè)線程中通過(guò)傳遞窗口句柄訪問(wèn)窗口的步驟為
(1) 定義一個(gè)消息號(hào)給要使用的操作;
(2) 為該消息在窗口類(lèi)中定義處理函數(shù);
(3) 在該窗口類(lèi)中增加消息映射;
(4) 用PostMessage或SendMessage在其他線程中發(fā)消息給該窗口。具體實(shí)現(xiàn)過(guò)程將在下一節(jié)做具體介紹。
Windows中用多媒體定時(shí)器實(shí)現(xiàn)定時(shí)功能首先需要把VS自帶的頭文件MMSystem.h 和靜態(tài)庫(kù)WinMM.lib 添加到工程文件夾,并在程序中添加語(yǔ)句“#include "MMSystem.h#pragma comment(lib,”winmm.lib”)”。MMSystem包含windows中與多媒體有關(guān)的大部分接口,WinMM也是與媒體播放有關(guān)的靜態(tài)庫(kù)。
其主要體步驟如下:
(1) 在主窗口頭文件中定義消息。為要使用的操作WM_ONDRAW定義一個(gè)消息號(hào)。

(2) 在主窗口頭文件中定義響應(yīng)函數(shù)。在窗口類(lèi)中為該消息定義處理函數(shù)CWINDOW。

(3) 在主窗口源文件中定義線程

(4) 在主窗口源文件中添加消息映射

(5) 在主窗口源文件中添加實(shí)現(xiàn)函數(shù)

(6) 在所用線程中發(fā)送postmessage消息給窗口函數(shù)


在10ms的時(shí)間間隔內(nèi),程序運(yùn)行良好,運(yùn)行結(jié)果圖如圖1所示:

圖1 實(shí)驗(yàn)結(jié)果圖
繪圖程序顯示正常,圖1中X,Y通道的波形都可以正常顯示,分別如圖中紅色和綠色(位于下方的曲線)曲線所示不會(huì)出現(xiàn)assert錯(cuò)誤。
同時(shí),為了進(jìn)行對(duì)比,本文實(shí)現(xiàn)了Timer組件定時(shí)方法。每次運(yùn)行10分鐘后,分別保存多媒體定時(shí)器和Timer組件的采樣數(shù)據(jù)。實(shí)驗(yàn)數(shù)據(jù)結(jié)果如表1所示:

表1 實(shí)驗(yàn)結(jié)果對(duì)比
實(shí)驗(yàn)結(jié)果表明,10ms下,settimer函數(shù)會(huì)發(fā)生數(shù)據(jù)丟失問(wèn)題,而多媒體定時(shí)器方法可以保證數(shù)據(jù)完整性,運(yùn)行良好,定時(shí)更精確。
本文采用多媒體定時(shí)器的方法實(shí)現(xiàn)了精確定時(shí)。文中論述了實(shí)現(xiàn)過(guò)程,重點(diǎn)是窗口函數(shù)跨線程的實(shí)現(xiàn)原理及步驟。本文方法保證了采樣結(jié)果不丟失,實(shí)驗(yàn)效果良好。
[1] 多媒體定時(shí)器的定制和使用方法。王文武,王誠(chéng),郝燕玲等,[J]計(jì)算機(jī)應(yīng)用 2000年第3 期
[2] 多媒體定時(shí)器在EIT數(shù)據(jù)采集精度評(píng)價(jià)中的應(yīng)用。陶峰,史學(xué)濤等,[J]醫(yī)學(xué)衛(wèi)生裝備 2011年第2期
[3] 多線程下多媒體定時(shí)器在快速數(shù)據(jù)采集中的應(yīng)用。常發(fā)亮 劉靜,[J]計(jì)算機(jī)應(yīng)用 2003年第S1期
[4] MSDN library. http://msdn.microsoft.com/library
[5] 多線程處理:編程提示. http://msdn.microsoft.com/zh-cn/library/h14y172e
The Implementation of MFC Windows Message Cross-Thread Delivery in Multimedia Timer
Fu Yao, Han Chengshan
(Changchun Institute of Optics, Fine Mechanics and Physics, Chinese Academy of Sciences, Changchun 130033, China)
To achieve high-frequency data collection, it uses multimedia timer method to achieve precise timing on PC, while research to achieve a cross-thread the MFC window class messaging solution to the problem. Experimental results show that timing accuracy is high, precision timing up to 10 milliseconds, without data loss, running well.
Multimedia Timer; Cross-Thread; Windows Message Delivery
TP391.8
A
1007-757X(2014)06-0005-02
2014.03.15)
國(guó)家自然科學(xué)基金項(xiàng)目(61036015)
傅 瑤(1983-),女,中科院長(zhǎng)春光機(jī)所,助理研究員,博士,研究方向:計(jì)算機(jī)控制和圖像處理,長(zhǎng)春,130033
韓誠(chéng)山(1972-),男,中科院長(zhǎng)春光機(jī)所,研究員,博士,研究方向:空間相機(jī)自動(dòng)控制,長(zhǎng)春,130033