深入淺出win32多線程編程_第1頁
深入淺出win32多線程編程_第2頁
深入淺出win32多線程編程_第3頁
深入淺出win32多線程編程_第4頁
深入淺出win32多線程編程_第5頁
已閱讀5頁,還剩69頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

統(tǒng),最優(yōu)秀的序員也只能通過駐留內(nèi)存的方式實(shí)現(xiàn)所謂的"多任務(wù)",而如今的Win32操作系統(tǒng)卻可以一理解多線及其同步、互斥等通信方式是理解現(xiàn)代操作系統(tǒng)的關(guān)鍵一環(huán),當(dāng)我們精通了Win32多線因此,學(xué)習(xí)Win32多線不僅對理解Win32本身有重要意義,而且對學(xué)習(xí)和其它操作系統(tǒng)也有觸類進(jìn)與進(jìn)(roce)是具有一定獨(dú)立功能的序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動,是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。序只是一組指令的有序集合,它本身沒有任何運(yùn)行的含義,只是一個(gè)靜態(tài)實(shí)因待資源或而被處于等待狀態(tài),因完成任務(wù)而被撤消,反映了一個(gè)序在一定的數(shù)據(jù)集上運(yùn)行的全部動態(tài)過。線和進(jìn)的關(guān)系是:線是屬于進(jìn)的,線運(yùn)行在進(jìn)空間內(nèi),同一進(jìn)所產(chǎn)生的線共享同一內(nèi)存空間,當(dāng)進(jìn)退出時(shí)該進(jìn)所產(chǎn)生的線都會被強(qiáng)制退出并清除。線可與屬于同一進(jìn)的其它線單進(jìn)、單線,MS-DOS大致是這種操作系統(tǒng)多進(jìn)、單線,多數(shù)UNIX(及類UNIX的LINUX)是這種操作系統(tǒng)多進(jìn)、多線,Win32(WindowsNT/2000/XP等)、Solaris2x和OS/2都是這種操作系統(tǒng)單進(jìn)、多線,VxWorks是這種操作系統(tǒng)在進(jìn)內(nèi)創(chuàng)建、終止線比創(chuàng)建、終止進(jìn)要快模型中,子進(jìn)必須父進(jìn)地址空間的問題。1、進(jìn)間通信剪貼板(Clip動態(tài)數(shù)據(jù)交換(DynamicData部件對象模型(ComponentObject文件映射(FileMap郵件槽(Mail管道Win32套接字過調(diào)用(RemoteProcedureWM_COPYDATA消息(WM_COPYDATAMessage)在WIN32中,可使用在PSAPI.DLL中提供的ProcessstatusHelper函數(shù)幫助我們獲取進(jìn)信息EnumProcesses()函數(shù)可以獲取進(jìn)的ID,其原型為參數(shù)lpidProcess:一個(gè)足夠大的DWORD類型的數(shù)組,用于存放進(jìn)的ID值;參數(shù)cb:存放進(jìn)ID值的數(shù)組的最大長度,是一個(gè)DWORD類型的數(shù)據(jù);參數(shù)cbNeeded:指向一個(gè)DWORD類型數(shù)據(jù)的指針,用于返回進(jìn)的數(shù)目;組中,進(jìn)個(gè)數(shù)存放在cbNeeded參數(shù)所指向的變量中;如果調(diào)用失敗,返回FALSE。GetModuleFileNameExA()函數(shù)可以實(shí)現(xiàn)通過進(jìn)句柄獲取進(jìn)文件名,其原型為DWORDDWORDGetModuleFileNameExA(HANDLEhProcess,HMODULElpstrFileName,DWORD參數(shù)hProcess:接受進(jìn)句柄的參數(shù),是HANDLE類型的變量;參數(shù)hModule:指針型參數(shù),在本文的序中取值為NULL;參數(shù)lpstrFileName:LPTSTR類型的指針,用于接受主調(diào)函數(shù)傳遞來的用于存放進(jìn)名的字符數(shù)組參數(shù)nsize:lpstrFileName名存放在lpstrFileName0////獲取當(dāng)前進(jìn)總數(shù)EnumProcesses(process_ids,sizeof(process_ids),for(inti=0;i<num_processes;{//根據(jù)進(jìn)IDprocess[i]=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,0,//if(GetModuleFileNameExA(process[i],NULL,File_name,cout<<fileName<<}Win32WIN32靠線的優(yōu)先級(達(dá)到搶占式多任務(wù)的目的)及分配給線的CPU時(shí)間來調(diào)度線。WIN32保存當(dāng)前執(zhí)行線的描述表(上下文裝入下一執(zhí)行線的描述表(上下文優(yōu)先級0為系統(tǒng)保留。它們可以分成兩類,即實(shí)時(shí)優(yōu)先級和可變優(yōu)先級:Win32對有者,甚至可以跨進(jìn)。有一組WIN32API與對象關(guān):WaitForSingleObject,用于等待對象的"激活",其函數(shù)原型WaitForSingleObject(HANDLEhHandle,//等待對象的句柄DWORDdwMilliseconds等待毫秒數(shù),INFINITEMemoryresourcenotification、Mutex、Process、Semaphore、Thread和Waitabletimer。如果等待的對象不可用,那么線就會掛起,直到對象可用線才會被喚醒。對不同的對象,WaitForSingleObject表現(xiàn)為不同的含義。例如,使用WaitForSingleObject(hThread,…)可以判斷一個(gè)線是否結(jié)束;使用WaitForSingleObject(hMutex,…)可以判斷是否能夠進(jìn)入臨界區(qū);而WaitForSingleObject(hProcess,…)則表現(xiàn)為等待一個(gè)進(jìn)的結(jié)束。bWaitAll,DWORDdwMilliseconds);CloseHandle在VC++6.0中,有兩種多線編方法:一是使用C運(yùn)行時(shí)庫及WIN32API函數(shù),另法是使用MFC,MFC對多線開發(fā)有強(qiáng)大的支持。VisualC++提供了兩種版本的C運(yùn)行時(shí)庫,-個(gè)版本供單線應(yīng)用序調(diào)用,另一個(gè)版本供多線應(yīng)用序類似errno的全局變量,每個(gè)線單獨(dú)設(shè)置一個(gè);VisualC++提供的多線運(yùn)行時(shí)庫又分為靜態(tài)庫和動態(tài)庫兩類,而每一類運(yùn)行時(shí)庫又可再分為debug版和release版,因此VisualC++共提供了6個(gè)運(yùn)行時(shí)庫。如下表:Singlethread(staticDebugsinglethread(staticMultiThread(staticDebugmultiThread(staticMultiThread(dynamic使用標(biāo)準(zhǔn)C庫(基于單線)并且只允重入函數(shù)集進(jìn)行庫調(diào)用使用Win32API線管理函數(shù),如Win32服務(wù)(EnterCriticalSectionLeaveCriticalSection函數(shù)),為不如果使用標(biāo)準(zhǔn)C庫而調(diào)用VC運(yùn)行時(shí)庫函數(shù),則在序的link階段會提示如下錯(cuò)誤errorLNK2001:errorLNK2001:unresolvedexternalsymbolendthreadexerrorLNK2001:unresolvedexternalsymbolWIN32線控制主要實(shí)現(xiàn)線的創(chuàng)建、終止、掛起和恢復(fù)等操作,這些操作都依賴于WIN32提供的一組API和具體編譯器的C運(yùn)行時(shí)庫函數(shù)。線函作為參數(shù),返回一個(gè)UINT,線函數(shù)的結(jié)構(gòu)為UINTUINTThreadFunction(LPVOID{ }{//Do}上this指針。請看下列序:#include#include"windowsh"#include<process.h>classExampleTask{voidStartTask();void{}intmain(intargc,char*{return0;}errorerrorC2664:'_beginthread':cannotconvertparameter1from'void(void*)'to'void(cdeclNoneofthefunctionswiththisnameinscopematchthetarget#include#include"windowsh"#include<process.h>classExampleTask{intmain(intargc,char*{ExampleTaskreturn0;}errorerrorC2664:'_beginthread':cannotconvertparameter1from'void(void*)'to'void(cdeclNoneofthefunctionswiththisnameinscopematchthetarget將該成員函數(shù)為static類型,去掉this指針;#include#include"windowsh"#include<process.h>classExampleTask{voidStartTask();void{}intmain(intargc,char*{return0;}#includeprocess.h>class{intintmain(intargc,char*{return0;}函數(shù)只能static成員。解決此問題的一種途徑是可以在調(diào)用類靜態(tài)成員函數(shù)(線函數(shù))時(shí)將this指針作為參數(shù)傳入,并在改線函數(shù)中用強(qiáng)制類型轉(zhuǎn)換將this轉(zhuǎn)換成指向該類的指針,通過該指針非靜態(tài)#include#include"windowsh"#include<process.h>classExampleTask{voidStartTask();{ExampleTask*pTaskMain=(ExampleTask*)//通過pTaskMain}void{}intmain(intargc,char*{return0;}進(jìn)的主線操作系統(tǒng)自動生成,Win32提供了CreateThreadAPI來完成用戶線的創(chuàng)建,該HANDLEHANDLELPSECURITY_ATTRIBUTESlpThreadAttributes,//PointertoaSECURITY_ATTRIBUTESSIZE_TdwStackSize,//Initialsizeofthestack,inLPVOIDlpParameter,//PointertoavariabletobepassedtothethreadDWORDdwCreationFlags,//FlagsthatcontrolthecreationofthethreadLPDWORDlpThreadId//Pointertoavariablethatreceivesthethreadidentifier用C/C++運(yùn)行時(shí)庫中的_beginthread(或_beginthreadex),其函數(shù)原型為:uintptr_tuintptr_tvoid(cdecl*start_address)(void*),//Startaddressofroutinethatbeginsexecutionofunsignedstack_size,//Stacksizefornewthreadorvoid*arglist//Argumentlisttobepassedtonewthreadoruintptr_tvoid*security,//PointertoaSECURITY_ATTRIBUTESstructureunsignedstack_size,unsigned(stdcall*start_address)(void*),void*arglist,unsignedinitflag,//Initialstateofnewthread(0forrunningorCREATE_SUSPENDEDforunsigned_beginthreadWin32API中的CreateThread通過_beginthread函數(shù)我們可以利用其參數(shù)列表arglist將多個(gè)參數(shù)傳遞到線_beginthread函數(shù)初始化某些C運(yùn)行時(shí)庫變量,若需要使用C運(yùn)行時(shí)庫線自身調(diào)用ExitThread函數(shù)即終止自己,其原型為VOIDVOIDExitThread(UINTfuExitCode它將參數(shù)fuExitCode設(shè)置為線的退出碼C/C++C/C++運(yùn)行時(shí)庫函數(shù)_endthread_endthreadex)終止線_endthread函數(shù)對于線內(nèi)的條件終止很有用。例如,專門用于通信處理的線若無法獲取對通信端口的同一進(jìn)或其他進(jìn)的線調(diào)用TerminateThread函數(shù),其原型為該函數(shù)用來結(jié)束由hThread參數(shù)指定的線,并把dwExitCode設(shè)成該線的退出碼。當(dāng)某個(gè)線不再包含線的進(jìn)終止當(dāng)我們創(chuàng)建線的時(shí)候,如果給其傳入CREATE_SUSPENDED標(biāo)志,則該線創(chuàng)建后被掛起,我們應(yīng)使用ResumeThread恢復(fù)它:如果ResumeThread函數(shù)運(yùn)行成功,它將返回線的前一個(gè)暫停計(jì)數(shù),否則返回0xFFFFFFFF。對于沒有被掛起的線,序員可以調(diào)用SuspendThread函數(shù)強(qiáng)行掛起之:一個(gè)線可以被掛起多次。線可以自行暫停運(yùn)行,但是不能自行恢復(fù)運(yùn)行。如果一個(gè)線被掛起次,則該線也必須被恢復(fù)n次才可能得以執(zhí)行 函數(shù)改變線的相對優(yōu)先級。一個(gè)線的優(yōu)先級是相對于其所屬進(jìn)的優(yōu)先級而言的BOOLBOOLSetThreadPriority(HANDLEhThread,int其中參數(shù)hThread是指向待修改優(yōu)先級線的句柄,線與包含它的進(jìn)的優(yōu)先級關(guān)系如下:線優(yōu)先級=進(jìn)類基本優(yōu)先級+線相對優(yōu)先級高:HIGH低于正常:BELOW_NORMAL空閑:IDLE_PRIORITY_CLASS最低線低于正常線正常線:THREAD_PRIORITY_NORMAL(缺省高于正常線最高線HANDLEHANDLEhCurrentThread=//獲得該線句柄SetThreadPriority(hCurrentThread,該函數(shù)可使線暫停自己的運(yùn)行,直到dwMilliseconds毫秒過去為止。它告訴系統(tǒng),自身不想在某個(gè)IntIntGetThreadPriority(HANDLEBOOLBOOLGetExitCodeThread(HANDLEhThread,我們可通過GetLastError()獲知錯(cuò)誤原因。如果線尚未結(jié)束,lpExitCode帶回來的將是STILL_ALIVE。獲得獲得/設(shè)置線上下文BOOLGetThreadContext(BOOLSetThreadContext(HANDLE由于GetThreadContext和SetThreadContext可以操作CPU內(nèi)部的寄存器,因此在一些高級技巧的編中有一定應(yīng)用。譬如,調(diào)試器可利用GetThreadContext掛起被調(diào)試線獲取其上下文,并設(shè)置上下文中的標(biāo)志寄存器中的陷阱標(biāo)志位,最后通過SetThreadContext使設(shè)置生效來進(jìn)行單步調(diào)試。以下序使用CreateThread創(chuàng)建兩個(gè)線,在這兩個(gè)線Sleep一段時(shí)間,主線通GetExitCodeThread來判斷兩個(gè)線是否結(jié)束運(yùn)行#include<stdioh>#include<stdlibh>#include<conioh>DWORDWINAPIint{HANDLEhThrd1;HANDLEhThrd2;DWORDthreadId;hThrd1=CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId);if(hThrd1)printf("Thread1hThrd2=CreateThread(NULL,0,ThreadFunc,(LPVOID)2,0,&threadId);if(hThrd2)printf("Thread2//KeepwaitinguntilbothcallstoGetExitCodeThreadsucceed//neitherofthemreturnsSTILL_ACTIVE.for(;;){printf("Pressanykeytoif(exitCode1==STILL_ACTIVE)puts("Thread1isstillrunning!");if(exitCode2==STILL_ACTIVEputs("Threadputs("Thread2isstillif(exitCode1!=STILL_ACTIVE&&exitCode2!=STILL_ACTIVE}printf("Thread1returned%d\n",exitCode1);printf("Thread2returned%d\n",return}*Takethestartupvalue,dosomesimplemathon*andreturnthecalculated{return(DWORD)n*10;}#include<stdioh>#include<stdlibh>DWORDWINAPIint{HANDLEhThrd;inti;for(i=0;i<5;{hThrd=CreateThread(NULL,0,ThreadFunc,(LPVOID)i,0,&threadId);if(hThrd){{printf("Threadlaunched%d\n",}}//Waitforthethreadstoreturn}{intfor(i=0;i<10;i++)printf("%d%d%d%d%d%d%d%d\n",n,n,n,n,n,n,n,n);return}運(yùn)行的輸出具有很大的隨機(jī)性,這里了幾次結(jié)果的一部分(幾乎每一次都不同如果我們使用標(biāo)準(zhǔn)C庫函數(shù)而不是多線版的運(yùn)行時(shí)庫,則序可能輸出" 下列序在主線創(chuàng)建一個(gè)SecondThread,在SecondThread線通過自增對Counter計(jì)數(shù)//WaituntilsecondthreadterminatesWaitForSingleObject(hThread,INFINITE);//WaituntilsecondthreadterminatesWaitForSingleObject(hThread,INFINITE);printf("Countershouldbe }//CreatethesecondhThread=(HANDLE)_beginthreadex(NULL,0,&SecondThreadFunc,NULL,0,printf("Creatingsecondint{unsignedreturn0;})while(Counter stdcallSecondThreadFunc(void{printf("Insecond#include<stdioh>線互斥是指對于共享的操作系統(tǒng)資源(指的是廣義的"資源",而不是Windows的.res文件,譬如(1)信號量互斥量臨界區(qū)(Criticalsection)intintvar;UINT{var=while(var<{// ::InterlockedIncrement(long*)}return}請看下列序intglobalFlag={return}int{HANDLEhThrd;DWORDhThrd=CreateThread(NULL,0,ThreadFunc,NULL,0,ifif{}while;}上述序中使用全局變量和while循環(huán)查詢進(jìn)行線間同步,實(shí)際上,這是一種應(yīng)該避免的方法,當(dāng)主線必須使自己與ThreadFunc函數(shù)的完成運(yùn)行實(shí)現(xiàn)同步時(shí),它并沒有使自己進(jìn)入睡眠狀態(tài)由于主線沒有進(jìn)入睡眠狀態(tài),因此操作系統(tǒng)繼續(xù)為它調(diào)度CPU時(shí)間,這就要占用其他線的寶貴時(shí)間的情況。因?yàn)樵谶@種情況下,系統(tǒng)決不會將任何時(shí)間片分配給ThreadFunc線。發(fā)狀態(tài)(unsignalorfalse)。根據(jù)狀態(tài)變遷方式的不同,可分為兩類:手動設(shè)置:這種對象只可能用序手動設(shè)置,在需要該或者發(fā)生時(shí),采用SetEventResetEvent來進(jìn)行設(shè)CreateEvent(LPSECURITY_ATTRIBUTESSECURITY_ATTRIBUTES結(jié)構(gòu)指針,可為NULLBOOLbManualReset,//手動///TRUE:在WaitForSingleObject后必須手動調(diào)用ResetEvent//FALSE:在WaitForSingleObject后,系統(tǒng)自動清 信BOOLbInitialStateLPCTSTRlpName 使用""機(jī)制應(yīng)注意以下事項(xiàng)由于event對象屬于內(nèi)核對象,故進(jìn)B可以調(diào)用OpenEvent函數(shù)通過對象的名字獲得進(jìn)A中照變量名來該結(jié)構(gòu)體。VOIDVOIDInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection//指向序員定義的CRITICAL_SECTION該函數(shù)用于對pcs所指的CRITICAL_SECTION結(jié)構(gòu)體進(jìn)行初始化。該函數(shù)只是設(shè)置了一些成員變量,VOIDVOIDDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection//指向一個(gè)不再需要的CRITICAL_SECTION變VOIDVOIDEnterCriticalSection(ION//指向一個(gè)你即將鎖定的CRITICAL_SECTIONVOIDVOIDLeaveCriticalSection(////指向一個(gè)你即將離開的CRITICAL_SECTIONvoidvoid{...//dosomething}每個(gè)共享資源使用一個(gè)CRITICAL_SECTION如果需要同時(shí)多個(gè)資源,則可能連續(xù)調(diào)用CriticalSection不是OS對象,如果進(jìn)入臨界區(qū)的線"掛"了,將無法釋放臨界資源。這個(gè)缺點(diǎn)在Mutex中得到了彌補(bǔ)。互斥量的作用是保證每次只能有一個(gè)線獲得互斥量而得以繼續(xù)執(zhí)行,使用CreateMutex函數(shù)創(chuàng)建CreateMutex(LPSECURITY_ATTRIBUTES//安全屬性結(jié)構(gòu)指針,可為NULLBOOLbInitialOwner,LPCTSTRlpNameMutex是對象,可以跨進(jìn),下面的代碼給出了從另一進(jìn)命名Mutex的例子HANDLEHANDLEif…}…}ReleaseMutex(HANDLEvoidvoid{...//dosomething}互斥(te)內(nèi)核對象能夠確保線擁有對單個(gè)資源的互斥權(quán)。互斥對象的行為特性與臨界區(qū)相texCritlSction的如下不同:不同進(jìn)的多個(gè)線能夠單個(gè)互斥對象信號量是0到指定最大值之間的同步對象。信號量狀態(tài)在其計(jì)數(shù)大于0時(shí)是有信號的,而其計(jì)數(shù)是0時(shí)是無信號的。信號量對象在控制上可以支持有限數(shù)量共享資源的。HANDLECreateSemaphoreHANDLECreateSemaphore(LONGl umCount,//最大資源數(shù)通過調(diào)用ReleaseSemaphore函數(shù),線就能夠?qū)π艠?biāo)的當(dāng)前資源數(shù)量進(jìn)行遞增,該函數(shù)原型為BOOLBOOLReleaseSemaphore(LONGlReleaseCount,信號量的當(dāng)前資源數(shù)增加lReleaseCountLPLONGlpPreviousCountHANDLEHANDLEOpenSemaphore(DWORDfdwAccess,BOOLbInherithandle,PCTSTRintintglobalVar={returnreturn}{return0;}movmoveax,[globalVarDaddmov[globalVar在"moveax,[globalVar(0042d3f0)]"指令與"addeax,1"指令以及"addeax,1"指令與"mov[globalVar用InterlockedExchangeAdd函數(shù)解決這個(gè)問題:intintglobalVar={return0;}{return0;}InterlockedExchangeAdd保證對變量globalVar的具有"原子性"。互鎖的控制速度非???,調(diào)CPU50,不需要進(jìn)行用戶方式與內(nèi)核方式的切換(該切換通常需要運(yùn)行1000個(gè)CPU周期)。CreateWaitableTimer(BOOLfManualReset,//可等待定時(shí)器對象在非激活狀態(tài)下被創(chuàng)建,序員應(yīng)調(diào)用SetWaitableTimer函數(shù)來界定定時(shí)器在何時(shí)BOOLBOOL//LONGlPeriod,//指明此后定時(shí)器應(yīng)該間隔多長時(shí)間激活一次 BOOLfResume);BOOlBOOlWaitableTimer(HANDLEhTimer(DWORDfdwAccess,BOOLbInherithandle,PCTSTR#include<stdioh>{longiThreadID;while{printf("\n線 printf("\n線 printf("\n線1釋放兩個(gè)臨界區(qū)");return}longWINAPIThreadFn(long{while{printf("\n線 printf("\n線 printf("\n線2釋放兩個(gè)臨界區(qū)}線1占用臨界區(qū)1或或或如果線2的控制函數(shù)改為longlongWINAPIThreadFn(long{while{printf("\n線21");printf("\n線22");printf("\n線2釋放兩個(gè)臨界區(qū)");}消除了線1、2相互等待資源的可能性。*AfxBeginThread(,//intnPriorityTHREAD_PRIORITY_NORMAL線的優(yōu)先級UINTnStackSize0,線DWORDdwCreateFlags0,線LPSECURITY_ATTRIBUTESlpSecurityAttrsNULL線的安全////線控制函數(shù){if(lpObjectNULL||!lpObject->IsKindof(RUNTIME_CLASS(CExampleClass)))return-1;//輸入?yún)?shù)//線成功啟動while{}return}//在 UI創(chuàng)建用戶界面線時(shí),必須首先從CWinThread派生類,并使用DECLARE_DYNCREATEIMPLEMENT_DYNCREATE宏此類下面給出了CWinThread類的原型(添加了關(guān)于其重要函數(shù)功能和是否需要被繼承類重載的注釋classclassCWinThread:public{//ConstructorsBOOLCreateThread(DWORDdwCreateFlags=0,UINTnStackSize=0,LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL);//CWnd*CWnd*m_pMainWnd;//mainwindow(usuallysameAfxGetApp()->m_pMainWnd)CWnd*m_pActiveWnd;//activemainwindow(maynotbem_pMainWnd)BOOLm_bAutoDelete;//enables'deletethis'afterthread//onlyvalidwhilerunningHANDLEm_hThread;//thisthread'sHANDLEoperatorHANDLE()DWORDm_nThreadID;//thisthread'sintBOOLSetThreadPriority(int//OperationsDWORDDWORD ram,LPARAM////virtualBOOL//runningandidle//virtualint//消息調(diào)度到TranslateMessage和 essage之前對其進(jìn)行篩選virtualBOOLPumpMessage();//lowlevelmessagevirtualBOOLOnIdle(LONGlCount);//returnTRUEifmoreidleprocessingvirtualBOOLIsIdleMessage(MSG*pMsg);//checksforspecialmessages//virtualintExitInstance();//defaultwill'delete//截獲由線的消息和命令處理 virtualLRESULTProcessWndProcException(CException*e,constMSG*//Advanced:handlingmessagessenttomessagefiltervirtualBOOLProcessMessageFilter(intcode,LPMSG////Advanced:virtualaccesstom_pMainWndvirtualCWnd*GetMainWnd();#ifdef_DEBUGvirtualvoidAssertValid()virtualvoidDump(CDumpContext&dc)intm_nDisablePumpCount;//Diagnostictraptodetectillegalre-entrancyvirtualvoidDelete();//'deletethis'onlyifm_bAutoDelete==//messagepumpforRunMSGm_msgCur;//currentmessage//constructorusedbyimplementationofCWinThread(AFX_THREADPROCpfnThreadProc,LPVOID//validafterLPVOIDm_pThreadParams;//genericparameterspassedtostartingfunctionAFX_THREADPROCm_pfnThreadProc;//setafterOLEisvoid(AFXAPI*m_lpfnOleTermOr COleMessageFilter*m_pMessageFilter;CPointm_ptCursorLast;//lastmousepositionUINTm_nMsgLast;//lastmousemessageBOOLDispatchThreadMessageEx(MSG*msg);//helpervoidDispatchThreadMessage(MSG*msg);//obsolete啟動UI線的AfxBeginThread函數(shù)的原型為CWinThreadCWinThread//從CWinThreadRUNTIME_CLASSCRuntimeClass*pThreadClass,UINTnStackSize=0,DWORDdwCreateFlags=0,DWORDdwCreateFlags=0,我們可以方便地使用VC++6.0類向?qū)Фx一個(gè)繼承自CWinThread的用戶線類。下面給出產(chǎn)生我們自定義的CWinThread子類CMyUIThread的方法。打開VC++6.0BaseClass類為CWinThreadCMyUIThread,點(diǎn)擊"OK"按鈕后就產(chǎn)生了類CMyUIThread。//CMyUIThreadclassCMyUIThread:public{CMyUIThread();//protectedconstructorusedbydynamic//////ClassWizardgeneratedvirtualfunctionvirtualintExitInstance();virtual//Generatedmessagemap//NOTE-theClassWizardwilladdandremovememberfunctions//IMPLEMENT_DYNCREATE(CMyUIThread,BOOL{//TODO:performandper-threadinitializationherereturnTRUE;}int{//TODO:performanyper-threadcleanupherereturnCWinThread::ExitInstance();}BEGIN_MESSAGE_MAP(CMyUIThread,//NOTE-theClassWizardwilladdandremove macrosCMyUIThread*pThread;CMyUIThread*pThread;另外,我們也可以不用AfxBeginThread創(chuàng)建線,而是分如下兩步完成調(diào)用CWinThread::CreateThread函數(shù)來啟動該線自身內(nèi)調(diào)用AfxEndThread函數(shù)可以終止該線voidvoidUINTnExitCode//theexitcodeofthe候捷先生早些時(shí)間喜歡為MDI序的每個(gè)窗口創(chuàng)建一個(gè)線,他后來澄清了這個(gè)錯(cuò)誤。因?yàn)槿绻€間通MFCCSyncObjectCCriticalSection、CCEvent、CMutex、CSemaphore類封裝和CCriticalSection、CCEvent、CMutex、CSemaphore類,下面是CSyncObjectclassclassCSyncObject:public{//HANDLEm_hObject;//virtualBOOLLock(DWORDdwTimeout=INFINITE);virtualBOOLUnlock()=0;virtualBOOLUnlock(LONG/*lCount*/,LPLONG/*lpPrevCount=NULL{returnTRUE;#ifdef_DEBUGCStringm_strName;virtualvoidAssertValid()virtualvoidDump(CDumpContext&dc)const;friendclassCSyncObject類最主要的兩個(gè)函數(shù)是Lock和Unlock,若我們直接使用CSyncObject類及其派生類,我們需要非常地在Lock之后調(diào)用Unlock。序提供了更靈活的機(jī)制,下面以實(shí)際來闡述CSingleLock的用法:classclass{{m_pCWnd=}voidvoidPaintBall(COLORREFcolor,CRect&rc);CWndvoidCThreadSafeWnd::PaintBall(COLORREFcolor,CRect{if(csl.Lock());{//notCDC*pdc=m_pCWnd->GetDC();CBrushCBrush*oldbrush=pdc-GdiFlush();//don'twaittoupdatethedis }}上述實(shí)例講述了用CSingleLockWindowsGDI相關(guān)對象進(jìn)行保護(hù)的方法,下面再給出一個(gè)其他方面intarray1[10],array2[10];CMutexSectionintarray1[10],array2[10];CMutexSectionsection;創(chuàng)建一個(gè)CMutex類的對象//賦值線控制函數(shù){for(inti=0;i<10;array1[i]=i;}//拷貝線控制函數(shù){for(inti=0;i<10;i++)array2[i]=array1[i];}}AfxBeginThread(CopyThread,NULL);//啟動拷貝線上面的例子中啟動了兩個(gè)線EvaluateThread和CopyThread,線EvaluateThread把10個(gè)數(shù)賦值給數(shù)組array1[],線CopyThread將數(shù)組array1[]拷貝給數(shù)組array2[]。由于數(shù)組的拷貝和賦值都是整體行為,forfor(inti=0;i<10;i++)array1[i]=i;和forfor(inti=0;i<10;array2[i]=可以利用PostThreadMessage函數(shù)間發(fā)送消息:BOOLBOOLPostThreadMessage(DWORDidThread,//threadidentifierUINTMsg,//messagetopost ram,//firstmessageLPARAMlParam//secondmessage"定理""定理" 屏幕上的每一個(gè)控件都是一個(gè)窗口,有對應(yīng)的窗口函數(shù)消息的發(fā)送通常有兩種方式,一是SendMessage,一是PostMessage,其原型分別LRESULTLRESULTSendMessage(HWNDhWnd,//handleofdestinationUINTMsg,//messageto ram,//firstmessageparameterLPARAMlParam//secondmessageBOOLPostMessage(HWNDhWnd,//handleofdestinationUINTMsg,//messageto ram,//firstmessageparameterLPARAMlParam//secondmessage兩個(gè)函數(shù)原型中的四個(gè)參數(shù)的意義相但是SendMessage和PostMessage的行為有差SendMessage必另一個(gè)線,則會發(fā)生線上下文切換,等待另一線理完成消息。為了防止另一線掉,導(dǎo)致SendMessage不能返回,我們可以調(diào)用SendMessageTimeout函數(shù):SendMessageTimeout(HWNDhWnd,//handleofdestinationwindowUINTMsg,//messageto ram,//firstmessageparameterLPARAMlParam,//secondmessageUINTfuFlags,//howtosendthemessageUINTuTimeout,//time-outdurationLPDWORDlpdwResult//returnvalueforsynchronous系,為此我們需要簡單地?cái)⑹鲆幌翸FC序的"生死因果"(:《深入淺出MFC》)。使用VC++6.0的向?qū)瓿梢粋€(gè)最簡單的單文檔架構(gòu)MFC應(yīng)用序輸入MFCEXE工名選擇單文檔架構(gòu),不支 /View結(jié)構(gòu)MFCThreadhclassclassCMFCThreadApp:public{////ClassWizardgeneratedvirtualfunctionvirtualBOOL//afx_msgvoid//NOTE-theClassWizardwilladdandremovememberfunctions//DONOTEDITwhatyouseeintheseblocksofgeneratedcodeMFCThread.cpp文//CMFCThreadAppBOOL{…CMainFrame*pFrame=newCMainFrame;m_pMainWnd=pFrame;//createandloadtheframewithits//Theoneandonlywindowhasbeeninitialized,soshowandupdateit.return}}#include#include"ChildViewclassCMainFrame:public{////ClassWizardgeneratedvirtualfunctionvirtualBOOLOnCmdMsg(UINTnID,intnCode,void*pExtra,#ifdef_DEBUGvirtualvoidAssertValid()virtualvoidDump(CDumpContext&dc)const;CChildView//NOTE-theClassWizardwilladdandremovememberfunctions//DONOTEDITwhatyouseeintheseblocksofgenerated//NOTE-theClassWizardwilladdandremove macros//DONOTEDITwhatyouseeintheseblocksofgeneratedcode//CMainFrame{//TODO:addmemberinitializationcode}BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&{if(!CFrameWnd::PreCreateWindow(cs)return//TODO:ModifytheWindowclassorstyleshereby//theCREATESTRUCTcs.dwExStyle&=cs.lpszClass=AfxRegisterWndClass(0);returnTRUE;}ChildViewh////CChildViewclassCChildView:public{////ClassWizardgeneratedvirtualfunctionvirtualBOOLPreCreateWindow(CREATESTRUCT&virtual//Generatedmessagemapfunctionsafx_msgvoidChildView.cpp//BEGIN_MESSAGE_MAP(CChildView,CWnd//CChildViewmessageBOOLCChildView::PreCreateWindow(CREATESTRUCT&{{ifreturncs.dwExStyle|=cs.style&=~WS_BORDER;cs.lpszClass=return}void{CPaintDCdc(this);//devicecontextfor//TODO:Addyourmessagehandlercode//DonotcallCWnd::OnPaint()forpainting}文件MFCThreadh和MFCThread.cpp定義的類CMFCThreadApp繼承自CWinApp類,而CWinApp類又繼承自CWinThread類(CWinThread類又繼承自CCmdTarget類),CMFCThread本質(zhì)上是一個(gè)MFC線類,下圖給出了相關(guān)的類層次結(jié)構(gòu):classclassCWinApp:public{//CWinApp(LPCTSTRlpszAppName=NULL);//defaultapp////Startupargs(donotchange)HINSTANCEm_hInstance;LPTSTRm_lpCmdLine;intint//Runningargs(canbechangedinLPCTSTRm_pszAppName;//humanreadablenameLPCTSTRm_pszExeName;//executablename(nospaces)LPCTSTRm_pszHelpFilePath;//defaultbasedonmodulepathLPCTSTRm_pszProfileName;//defaultbasedonappname//virtualBOOLInitInstance();virtualintExitInstance();//returnappexitcodevirtualintRun();virtualBOOLOnIdle(LONGlCount);//returnTRUEifmoreidleprocessingvirtualLRESULTProcessWndProcException(CException*e,constMSG*pMsg);SDK序的WinMain所完成的工作現(xiàn)在由CWinApp的三個(gè)函數(shù)完成virtualBOOLInitInstance();virtualintRun();"CMFCThreadApptheApp;"語句定義的全局變量theApp是整個(gè)式的applicationobject,每一個(gè)MFC應(yīng)用序都有一個(gè)。當(dāng)我們執(zhí)行MFCThread序的時(shí)候,這個(gè)全局變量被構(gòu)造。theApp配置完成后,WinMain開始執(zhí)行。但是序中并沒有WinMain的代碼,它在哪里呢?原來MFC早已準(zhǔn)備好并由Linker直接加到應(yīng)用序代碼中的,其原型為(存在于VC++6.0安 下提供的APPMODUL.CPP文件中externextern"C"intLPTSTRlpCmdLine,intnCmdShow){//callshared/exported}其中調(diào)用的AfxWinMain如下(存在于VC++6.0安 LPTSTRLPTSTRlpCmdLine,int{ASSERT(hPrevInstance==intnReturnCode=-1;CWinApp*pApp=//AFXinternalif(!AfxWinInit(hInstance,hPrevInstance,lpCmdLine,goto//Appglobalinitializationsif(pApp!=NULL&&!pApp-gotoif(!pThread->InitInstance()){if(pThread->m_pMainWnd!={}gotoInitFailure;}nReturnCode=pThread-#ifdef//CheckformissingAfxLockTempMapif(AfxGetModuleThreadState()->m_nTempMapLock!={TRACE1("Warning:Tempmaplockcountnon-zero(%ld).\n",}}CWinApp*pApp=AfxGetApp();其中,InitApplication是窗口類別的場所;InitInstance是產(chǎn)生窗口并顯示窗口的場所;Run是提取并分派消息的場所。這樣,MFC就同WIN32SDK序?qū)?yīng)起來了。CWinThread::Run是序生命的"活水"(:《深入淺出MFC》,函數(shù)存在于VC++6.0安裝下提供的THRDCORE.CPP文件中):////mainrunningroutineuntilthreadexitsintCWinThread::Run(){//fortrackingtheidletimeBOOLbIdle=LONGlIdleCount=//acquireanddispatchmessagesuntilaWM_QUITmessageisreceived.for(;;){//phase1:checktoseeifwecandoidle{//callOnIdlewhileinbIdlestateif(!OnIdle(lIdleCount++))bIdle=FALSE;//assume"noidle"}//phase2:pumpmessageswhileavailable{//pumpmessage,butquitonWM_QUITif(!PumpMessage())return//reset"noidle"stateafterpum if(IsIdleMessage(&m_msgCur)){bIdlebIdle=TRUE;lIdleCount=}}while(::PeekMessage(&m_msgCur,NULL,NULL,NULL,}ASSERT(FALSE);//not}//CWinThreadimplementationBOOL{if(!::GetMessage(&m_msgCur,NULL,NULL,{return}//processthisif(m_msgCurmessage!=WM_KICKIDLE&&{ }return}因此,忽略IDLE狀態(tài),整個(gè)RUNdodo }while消息的"繞行"過在MFC中,只要是CWnd衍生類別,就可以攔下任何Windows消息。與窗口無關(guān)的MFC類別(例如 和CWinApp)如果也想處理消息,必須衍生自CCmdTarget,并且只可能收MANDMESSAGE_MAP的類都繼承自CCmdTargetMFC中MESSAGE_MAP的定義依賴于以下三個(gè)宏theClass,//SpecifiesthenameoftheclasswhosemessagemapthisisbaseClass//SpecifiesthenameofthebaseclassoftheClass我們序中涉及到的有:MFCThread.h、MainFrmh、ChildView.h文//NOTE-theClassWizardwilladdandremove macros//DONOTEDITwhatyouseeintheseblocksofgenerated//NOTE-theClassWizardwilladdandremove macros//DONOTEDITwhatyouseeintheseblocksofgeneratedcode)由這些宏,MFC建立了一個(gè)消息映射表(消息流動網(wǎng)),按照消息流動網(wǎng)匹配對應(yīng)的消息處理函數(shù),看到這里相信你有這樣的疑問:序定義了CWinApp類的theApp全局變量,可是從來沒有調(diào)AfxBeginThread或theApp.CreateThread啟動線呀,theApp對應(yīng)的線是怎么啟動的在CWinApp的構(gòu)造函數(shù)里,MFC將theApp"對應(yīng)"向了這個(gè)線,具體的實(shí)現(xiàn)是這樣的:{if(lpszAppName!=NULL)m_pszAppName=//initializeCWinThreadAFX_MODULE_STATE*pModuleState=ASSERT(AfxGetThread()==NULL);ASSERT(AfxGetThread()==this);m_hThread=::GetCurrentThread();m_nThreadID=::GetCurrentThreadId();//initializeCWinAppstateASSERT(afxCurrentWinApp==NULL);//onlyoneCWinAppobjectpleaseASSERT(AfxGetApp()==this);//innon-runningstateuntilWinMainm_hInstance=NULL;m_pszHelpFilePath=NULL;m_pszProfileName=NULL;m_pszRegistryKey=NULL;m_pszExeName=NULL;m_pRecentFileList=NULL;m_pDocManager=NULL;m_lpCmdLine=NULL;m_pCmdInfo=NULL;//initializewaitcursorstatem_nWaitCursorCount=0;//initializecurrentprinterstatem_hDevMode=NULL;m_hDevNames=NULL; ges=0;//notspecified(defaultsto//initializeDAOm_lpfnDaoTerm=NULL;//willbesetifAfxDaoInit//otherinitialization}很顯然,theApp成員變量都被賦予OS啟動的這個(gè)當(dāng)前線相關(guān)的值,如代碼m_hThreadm_hThreadGetCurrentThread();//theApp的線句柄等于當(dāng)前線句柄m_nThreadID::GetCurrentThreadId();//theApp的線ID等于當(dāng)前線所以CWinApp類幾乎只是為MFC序的第一個(gè)線量身定制的,它不需要也不能被AfxBeginThread或theApp.CreateThread"再次"CWinApptheAppUI線,不要繼承類CWinApp,而應(yīng)繼承類CWinThread。而參考第1節(jié),由于我們一般以主線(在MFC序里實(shí)際上就是OS啟動的第一個(gè)線)處理所有窗口的消息,所以我們幾乎沒有再啟動UI線在工業(yè)控制系統(tǒng)中,工控機(jī)(PCWindows平臺)經(jīng)常需要與單片機(jī)通過串口進(jìn)行通信。因此,操作和使用PC的串口成為大多數(shù)單片機(jī)、嵌入式系統(tǒng)領(lǐng)域工師必須具備的能力。下圖從Windows的"控制面板->系統(tǒng)->設(shè)備管理器->通信端口(COM1)"打開COM的設(shè)置窗口:WIN32平臺下,對通信端口進(jìn)行操作跟基本的文件操作一樣。創(chuàng)建/打開COM資源下列函數(shù)如果調(diào)用成功,則返回一個(gè)標(biāo)識通信端口的句柄,否則返回-WORDdwDesiredAccess,//對資源的 PSECURITY_ATTRIBUTESlpSecurityAttributes,//安全描述符指針,可為NULLWORDdwFlagsAndAttributes,//文件屬性,可為NULL teFile//模板文件句柄,置為獲得/COM屬下列函數(shù)可以獲得COMBOOLBOOLmState(HANDLEhFile,標(biāo)識LPDCBlpDCB指向一個(gè)設(shè)備控制塊(DCB結(jié)構(gòu))如果要調(diào)整通信端口的參數(shù),則需要重新配置設(shè)備控制塊,再用WIN32API mState(HANDLEhFile,標(biāo)識LPDCBlpDCB指向一個(gè)設(shè)備控制塊(DCB結(jié)構(gòu))DCB結(jié)構(gòu)包含了串口的各項(xiàng)參數(shù)設(shè)置,如typedeftypedefstruct{//DWORDDCBlength;//sizeof(DCB)DWORDBaudRate;//currentbaudDWORDfBinary:1;//binarymode,noEOFcheckDWORDfParity:1;//enableparitycheckingDWORDfOutxCtsFlow:1;//CTSoutputflowcontrolDWORDfOutxDsrFlow:1;//DSRoutputflowcontrolDWORDfDtrControl:2;//DTRflowcontroltypeDWORDfDsrSensitivity:1;//DSRsensitivityDWORDfTXContinueOnXoff:1;//XOFFcontinuesTxDWORDfOutX:1;//XON/XOFFoutflowcontrolDWORDfInX:1;//XON/XOFFinflowcontrolDWORDfErrorChar:1;//enableerrorre DWORDfNull:1;//enablenullstripDWORDfRtsControl:2;//RTSflowcontrolDWORDfAbortOnError:1;//abortreads/writesonerrorDWORDfDummy2:17;//WORDw ;//notcurrentlyusedWORDXonLim;//transmitXONthresholdWORDXoffLim;//transmitXOFFthresholdBYTEByteSize;//numberofbits/byte,4-8BYTEParity;//0-4=no,odd,even,mark,spaceBYTEStopBits;//0,1,2=1,1.5,2charXonChar;//TxandRxXONcharactercharXoffChar;//TxandRxXOFFcharactercharErrorChar;//errorre cementcharactercharEofChar;//endofinputcharactercharEvtChar;//receivedeventWORD1;};donot mMask(HANDLEhFile,標(biāo)識值A(chǔ)breakwasdetectedonTheCTS(clear-to-send)signalchangedAline-statuserroroccurred.Line-statuserrorsareCE_FRAME,andAringindicatorwasTheRLSD(receive-line-signal-detect)signalchangedAcharacterwasreceivedandcedintheinputTheeventcharacterwasreceivedandcedintheinputbuffer.Theeventisspecifiedinthedevice'sDCBstructure,whichisappliedtoaserialportbyusing mStatefunction.Thelastcharacterintheoutputbufferwas mEvent(HANDLEhFile,標(biāo) LPOVERLAPPEDlpOverlapped,//指向overlappedLPVOIDlpBuffer,//輸入數(shù)據(jù)Buffer指針DWORDnNumberOfBytesToRead,//需 的字節(jié)LPDWORDlpNumberOfBytesRead,//實(shí) 的字節(jié)數(shù)指LPOVERLAPPEDlpOverlappedoverlappedBOOLWriteFile(HANDLEhFile,//LPCVOIDlpBuffer,BufferDWORDnNumberOfBytesToWrite,//需要寫的字節(jié)數(shù)LPOVERLAPPEDlpOverlapped//指向overlapped結(jié)構(gòu)工實(shí)下面我們用第1節(jié)所述API實(shí)現(xiàn)一個(gè)多線的串口通信序。這個(gè)例子工(工名)的界面很簡單,如下圖所它是一個(gè)多線的應(yīng)用序,包括兩個(gè)工作者線,分別處理串口1和串口2。為了簡化問題,我們EV_RXCHAR)。在工實(shí)例的BOOL {NULL,OPEN_EXISTING,0,NULL);if(hComm1==(HANDLE)-{returnfalse;}{DCBmState(hComm1,&wdcb);}//打開并設(shè)置COM2if(hComm2==(HANDLE)-1){returnfalse;}{DCB}m_pMainWnd=&dlg;if(nResponse==IDOK){// cecodeheretohandlewhenthedialog//dismissedwith}elseif(nResponse=={// cecodeheretohandlewhenthedialog//dismissedwith}return}此后我們在 Dlg的初始化函數(shù)OnInitDialog中啟動兩個(gè)分別處理COM1COM2的線 {//Add itemto //IDM_ABOUTBOXmustbeinthesystemcommandASSERT(IDM_ABOUTBOX<0xF000); *pSys =GetSystem if(pSys !=NULL){CString if(!strAbout {--(MF_STRING,IDM_ABOUTBOX,}}//Settheiconforthisdialog.Theframeworkdoesthis//whentheapplication'smainwindowisnotadialogSetIcon(m_hIcon,TRUE);//SetbigiconSetIcon(m_hIcon,FALSE);//Setsmall//TODO:AddextrainitializationDWORDhCommThread1=::CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,if(hCommThread1=={AfxMessageBox("1");returnfalse;}DWORDhCommThread2=::CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,if(hCommThread2=={AfxMessageBox("AfxMessageBox("2");returnfalse;}returnTRUE;//returnTRUEunlessyousetthefocustoa}{DWORDwEven;while{if(wEven=0){hCommThread1=NULL;}{switch{caseif(wTxPos<{DWORDwCount;//寫入的字節(jié)數(shù)}caseif(com1Data.wRxPos<{ 串口數(shù)據(jù),DWORDwCount; if(com1Data.wRxPos==if(com1Data.wRxPos==::PostMessage(hWnd,COM_SENDCHAR,0,}}}}}return}{DWORDwEven;while{if(wEven=0){hCommThread2=NULL;}{switch{caseif(wTxPos<{DWORDwCount;//寫入的字節(jié)數(shù)WriteFile(hComm2,com2Data.TxBuf[wTxPos1,&wCount,NULL);}caseif(com2Data.wRxPos<{ 串口數(shù)據(jù)DWORDwCount; ReadFile(hComm2,com2Data.RxBuf[wRxPos],1,&wCount,}}}}return}線控制函數(shù)中所操作的com1Data和com2Data是與串口對應(yīng)的數(shù)據(jù)結(jié)構(gòu)structtagSerialPort的實(shí)例,typedeftypedefstruct{BYTERxBuf[SPRX_BUFLEN];//接收BufferWORDwRxPos;//當(dāng)前接收字節(jié)位置WORDwRxLen;//要接收的字節(jié)數(shù)BYTETxBuf[SPTX_BUFLEN];//發(fā)送BufferWORDwTxPos;//當(dāng)前發(fā)送字節(jié)位置WORDwTxLen;//要發(fā)送的字節(jié)數(shù)使用多線串口通信更方便的途徑是編寫一個(gè)多線的串口類,例如RemonSpekreijse編寫了一 串口類。仔細(xì)分析這個(gè)類的源代碼,將十分有助于我們對先前所學(xué)多線及同步知識的理解#ifndef#ifndef#defineM_BREAK_DETECTEDWM_USER+1//AbreakwasdetectedonM_CTS_DETECTEDWM_USER+2//TheCTS(clear-to-send)signalM_DSR_DETECTEDWM_USER+3//TheDSR(data-set-ready)signalM_ERR_DETECTEDWM_USER+4//Aline-statuserroroccurred.Line-statuserrorsareCE_FRAME,CE_OVERRUN,andCE_RXPARITY.M_RING_DETECTEDWM_USER+5//AringindicatorwasM_RLSD_DETECTEDWM_USER+6//TheRLSD(receive-line-signal-detect)signalchangedstate.M_RXCHARWM_USER+7//Acharacterwasreceived cedinthe M_RXFLAG_DETECTEDWM_USER+8//Theeventcharacterwasreceivedcedintheinput M_TXEMPTY_DETECTEDWM_USER+9//Thelastcharacterintheoutputbufferwassent.class{vir

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論