• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉(zhuǎn),開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            windows2000提供了如下幾種線程池函數(shù)用于線程管理:
            一、異步調(diào)用函數(shù):
            BOOL QueueUserWorkItem(
            PTHREAD_START_ROUTINE pfnCallback,
            PVOID pvContext,
            ULONG dwFlags);
            該函數(shù)將“工作項目”放入線程池并且立即返回。工作項目是指一個用pfnCallback參數(shù)標識的函數(shù)。它被調(diào)用并且傳遞單個參數(shù)pvContext.工作項目函數(shù)原型如下:
            DWORD WINAPI WorkItemFunc(PVOID pvContext);
            dwFlags參數(shù):WT_EXECUTEDEFAULT? 工作項目放入非I/O組件得線程中
            ???????????? WT_EXECUTEINIOTHREAD 工作項目放入I/O組件的線程中,這樣的線程在I/O請求沒有完成之前不會被終止運行????????????????????????????????? ,防止因為線程被終止導(dǎo)致I/O請求丟失。
            ???????????? WT_EXECUTEINPERSISTENTTHREAD 放入永久線程池,
            ???????????? WT_EXECUTELONGFUNCTION? 工作項目需要長時間的工作,系統(tǒng)會據(jù)此安排更多的線程。

            線程池不能設(shè)置線程個數(shù)的上限,否則排隊個數(shù)超過線程個數(shù)上限的時候,會導(dǎo)致所有的線程都被中斷。

            工作項目函數(shù)如果訪問了已經(jīng)被卸載的DLL,會產(chǎn)生違規(guī)訪問。


            二、按規(guī)定的時間間隔調(diào)用函數(shù)
            創(chuàng)建定時器隊列:
            HANDLE CreateTimerQueue();
            在隊列中創(chuàng)建定時器:
            BOOL CreateTimerQueueTimer(
            PHANDLE phNewTimer,
            HANDLE hTimerQueue,
            WAITORTIMERCALLBACK pfnCallback,
            PVOID pvContext,
            DWORD dwDueTime,
            DWORD dwPeriod,
            ULONG dwFlags);
            工作回調(diào)函數(shù)原型如下:
            VOID WINAPI WaitOrTimerCallback(
            PVOID pvContext,
            BOOL fTimerOrWaitFired);
            dwFlags比前面的多了一個標志:WT_EXECUTEINTIMERTHREAD,表示由組件的定時器線程(定時器組件只有一個線程)運行這個
            工作函數(shù),此時的工作函數(shù)必須是很快返回的,否則定時器組件將無法處理其他的請求。

            刪除定時器:
            BOOL DeleteTimerQueueTimer(
            HANDLE hTimerQueue,
            HANDLE hTimer,
            HANDLE hCompletionEvent);
            在定時器線程中刪除定時器會造成死鎖。設(shè)定hCompletionEvent為INVALID_HANDLE_VALUE,那么在定時器的所有排隊工作項目沒有完成之前,DeleteTimerQueueTimer不會返回,也就是說在工作項目中對定時器進行中斷刪除會死鎖。可以給hCompletionEvent傳遞事件句柄,函數(shù)會立即返回,在排隊工作完成之后,會設(shè)置該事件。

            重新設(shè)定定時器://不能修改已經(jīng)觸發(fā)的單步定時器。
            BOOL ChangeTimerQueueTimer(
            HANDLE hTimerQueue,
            HANDLE hTimer,
            ULONG dwDueTime,
            ULONG dwPeriod;

            刪除定時器隊列:
            BOOL DeleteTimerQueueEx(
            HANDLE hTimerQueue,
            HANDLE hCompletionEvent);

            三、當單個內(nèi)核對象變?yōu)橐淹ㄖ獱顟B(tài)時調(diào)用函數(shù)
            BOOL RegisterWaitForSIngleObject(
            PHANDLE phNewWaitObject,
            HANDLE hObject,
            WAITORTIMERCALLBACK pfnCallback,
            PVOID pvContext,
            ULONG dwMilliseconds,
            ULONG dwFlags);
            pfnCallBack原型:
            VOID WINAPI WaitOrTimerCallbadkFunc(
            PVOID pvContext,
            BOOLEAN fTimerorWaitFired);
            如果等待超時,fTimerorWaitFired==TRUE,如果是已通知狀態(tài),則為FALSE.

            dwFlags可以傳遞參數(shù):WT_EXECUTEINWAITTHREAD,它讓等待組件得線程之一運行工作項目函數(shù)。注意項同前。

            如果等待的內(nèi)核對象是自動重置的,那么會導(dǎo)致工作函數(shù)被反復(fù)調(diào)用,傳遞WT_EXECUTEONLYONCE會避免這種情況。

            取消等待組件的注冊狀態(tài):
            BOOL UnregisterWaitEx(
            HANDLE hWaitHandle,
            HANDLE hCompletionEvent);

            四、當異步I/O請求完成時調(diào)用函數(shù)
            將設(shè)備和線程池的非I/O組件關(guān)聯(lián)
            BOOL BindIoCompletionCallback(
            HANDLE hDevice,
            POVERLAPPED_COMPLETION_ROUTINE pfnCallback,
            ULONG dwFlags//始終為0);

            工作函數(shù)原型:
            VOID WINAPI OverlappedCompletionRoutine(
            DWORD dwErrorCode,
            DWORD dwNumberOfBytesTransferred,
            ???????????????????????? ,
            POVERLAPPED pOverlapped);

            Windows的內(nèi)存結(jié)構(gòu)

            從98,2000,到64位的windows,內(nèi)存管理方式都是不同的,32位的win2000用戶內(nèi)存是從0x10000到0x7fffffff(64kB-2G),2000 Advanced server可以達到(64kB-3G),其中最高64kB也是禁止進入的。再往上則由系統(tǒng)使用。98則是從0x400000-0x7fffffff(4M-2G),2G-3G是系統(tǒng)用來存放32位共享數(shù)據(jù)的地方,如很多系統(tǒng)動態(tài)連接庫。0-4M是為了兼容16位程序保留的。3G-4G由系統(tǒng)自身使用。98的內(nèi)核區(qū)是不受保護的,2000受保護。
            對虛擬地址空間的分配稱作保留,使用虛擬內(nèi)存分配函數(shù)(VirtualAlloc),釋放使用VirtualFree(),目前,所有cpu平臺的分配粒度都是64kB,頁面大小則不同,x86是4kB,Alpha是8kB,系統(tǒng)在保留內(nèi)存的時候規(guī)定要從分配粒度邊界開始,并且是頁面的整數(shù)倍,用戶使用VirtualAlloc都遵守這個規(guī)定,但系統(tǒng)不是,它是從頁面邊界開始分配的。

            將物理存儲器映射到保留的內(nèi)存區(qū)域的過程稱為提交物理存儲器,提交是以頁面為單位進行的,也使用VirtualAlloc函數(shù)。

            物理存儲器是由內(nèi)存和(硬盤上的)頁文件組成的,如果訪問的數(shù)據(jù)是在頁文件中,則稱為頁面失效,cpu會把訪問通知操作系統(tǒng),操作系統(tǒng)負責(zé)將數(shù)據(jù)調(diào)入內(nèi)存,并指導(dǎo)cpu再次運行上次失效的指令。

            當啟動一個程序的時候,系統(tǒng)并不是將整個文件讀入內(nèi)存或者頁文件,而是將這個文件直接映射到虛擬內(nèi)存空間,并將需要的數(shù)據(jù)讀入內(nèi)存,即將硬盤上的文件本身當作頁文件(雖然不是)。當硬盤上的一個程序的文件映像(這是個exe文件或者dll文件)用作地址空間的物理存儲器,它稱為內(nèi)存映射文件。當一個.exe或者dll文件被加載時,系統(tǒng)將自動保留一個地址空間的區(qū)域,并將該文件映射到該區(qū)域中。但系統(tǒng)也提供了一組函數(shù),用于將數(shù)據(jù)文件映射到一個地址空間的區(qū)域中。


            物理存儲器的頁面具有不同的保護屬性:
            PAGE_NOACESS
            PAGE_READONLY
            PAGE_READWRITE
            PAGE_EXECUTE
            PAGE_EXECUTE_READ
            PAGE_EXECUTE_READWRITE
            PAGE_WRITECOPY
            PAGE_EXECUTE_WRITECOPY
            后兩個屬性是配合共享頁面機制使用的。WINDOWS支持多個進程共享單個內(nèi)存塊,比如運行notepad的10個實例,可以讓他們共享應(yīng)用程序的代碼和數(shù)據(jù),這樣可以大大提高性能,但要求該內(nèi)存塊是不可寫的。于是系統(tǒng)在調(diào)入.exe或者dll的時候,會計算那些頁面是可以寫入的,為這些頁面分配虛擬內(nèi)存。然后同其他的頁面一起映射到一塊虛擬內(nèi)存,但賦PAGE_WRITECOPY或者PAGE_EXECUTE_WRITECOPY屬性(通常包含代碼的塊是PAGE_EXECUTE_READ,包含數(shù)據(jù)的塊是PAGE_READWRITE)。當一個進程試圖將數(shù)據(jù)寫入共享內(nèi)存塊時,系統(tǒng)會進行如下操作:尋找預(yù)先分配的一個空閑頁面,將試圖修改的頁面拷貝到這個空閑頁面,賦予PAGE_READWRITE或者PAGE_EXECUTE_READWRITE屬性,然后更新進程的頁面表,使得用戶可以對新的頁面進行寫入。

            還有三個特殊的保護屬性:PAGE_NOCACHE PAGE_WRITECOMBINE PAGE_GUARD,前兩個用于驅(qū)動程序開發(fā),最后一個可以讓應(yīng)用程序在頁面被寫入的時候獲得一個異常。

            塊的意思是一組相鄰的頁面,它們具有相同的保護屬性,并且受相同類型的物理存儲器支持。
            賦予虛擬內(nèi)存頁面保護屬性的意義是為了提高效率,而且這個屬性總會被物理存儲器的保護屬性取代。

            如果數(shù)據(jù)在內(nèi)存中沒有對齊,那么cpu要多次訪問才能得到數(shù)據(jù),效率很低。

            內(nèi)存管理函數(shù):

            獲得系統(tǒng)信息:
            VOID GetSystemInfo(LPSYSTEM_INFO psinf);//可以得到頁面大小,分配粒度,最大內(nèi)存地址,最小內(nèi)存地址。

            獲得內(nèi)存狀態(tài):
            VOID GlobalMemoryStatus(LPMEMORYSTATUS pmst);

            獲得內(nèi)存地址的某些信息:
            DWORD VirtualQuery(
            LPVOID pvAddress,
            PMEMORY_BASIC_INFORMATION pmbi,
            DWORD dwLength);

            DWORD VirtualQuery(
            HANDLE hProcess,
            LPVOID pvAddress,
            PMEMORY_BASIC_INFORMATION pmbi,
            DWORD dwLength);

            內(nèi)存映射文件的優(yōu)點:
            1 節(jié)省頁面文件;
            2 加快程序啟動;
            3 在多個進程間共享數(shù)據(jù)。

            進程的啟動過程:
            系統(tǒng)首先將.exe文件映射到地址空間,缺省基地址是0x400000,然后查詢.exe的輸入表,將其使用的所有.dll也映射到地址空間(基地址在每個.dll文件中,如果不能滿足,需要重定位),然后將執(zhí)行.exe的啟動代碼。此時.exe文件還在硬盤上。每次代碼跳到一個尚未加載到內(nèi)存的指令地址,就會出現(xiàn)一個錯誤,系統(tǒng)會發(fā)現(xiàn)這個錯誤,并將代碼加再到內(nèi)存中。
            如果再創(chuàng)建這個.exe文件的一個實例。那么直接將原來的地址空間中的內(nèi)容映射到新的地址空間就可以了。這樣多個實例就可以共享相同的代碼和數(shù)據(jù)。如果某個實例要改變共享內(nèi)容,系統(tǒng)就為要更改的頁面申請一個新的頁面,將內(nèi)容拷貝一份,然后用新的頁面代替地址空間中原來頁面的映射就可以了。98同2000不同,它不待修改便立即為所有的實例分配新的頁面。

            使用內(nèi)存映射文件:
            1 創(chuàng)建或打開一個文件內(nèi)核對象:
            HANDLE CreateFile(
            PCSTR pszFileName,
            DWORD dwDesiredAccess,
            DWORD dwShareMode,
            PSECURITY_ATTRIBUTES psa,
            DWORD dwCreationDisposition,
            DWORD dwFlagsAndAttributes,
            HANDLE hTemplateFile);
            失敗的返回值是INVALID_HANDLE_VALUE
            2 創(chuàng)建一個文件映射內(nèi)核對象:
            HANDLE CreateFileMapping(
            HANDLE hFile,
            PSECURITY_ATTRIBUTES psa,
            DWORD fdwProtect,
            DWORD dwMaximumSizeHigh,
            DWORD dwMaximumSizeLow,
            PCTSTR pszName);
            如果給函數(shù)的fdwProtect傳遞PAGE_READWRITE標志,那么磁盤上文件的大小會變?yōu)橥诚裎募嗤笮 ?br />失敗的返回值是NULL。

            3 將文件映射到進程的地址空間:
            PVOID MapViewOfFile(
            HANDLE hFileMappingObject,
            DWORD dwDesiredAccess,
            DWORD dwFileOffsetHigh,
            DWORD dwFileOffsetLow,
            SIZE_T dwNumberOfBytesToMap);
            windows2000會根據(jù)要求將部分文件映射到地址空間,而win98總是把全部內(nèi)容映射到地址空間,并且僅能映射到2G-3G空間,此空間為共享空間,所有的進程如果映射相同的文件,那么都會映射到相同的地址,一個進程甚至不必映射就可以訪問這個空間里其他進程的映射文件,win2000多個進程映射同一個文件返回的地址通常是不同的。
            4 從進程的地址空間中撤銷文件數(shù)句的映像
            BOOL UnmapViewOfFile(PVOID pvBaseAddress);

            將文件映像寫入磁盤:
            BOOL FlushViewOfFile(
            PVOID pvAddress,
            SIZE_T dwNumberOfBytesToFlush);

            windows保證單個文件映射對象的多個視圖具有相關(guān)性。但不保證但個文件的多個映射對象有相關(guān)性。

            使用MapViewOfFileEx代替MapViewOfFile可以設(shè)定文件映射的基地址:
            PVOID MapViewOfFileEx(
            HANDLE hFileMappingObject,
            DWORD dwDesiredAccess,
            DWORD dwFileOffsetHigh,
            DWORD dwFileOffsetLow,
            SIZE_T dwNumberOfBytesToMap,
            PVOID pvBaseAddress);

            使用內(nèi)存映射文件在進程間共享數(shù)據(jù)
            共享機制:RPC ,COM,OLE,DDE,窗口消息(WM_COPYDATA),剪貼板,郵箱,管道,套接字。
            在單機上,它們的底層實現(xiàn)方法都是內(nèi)存映射文件。

            可以在頁文件中直接創(chuàng)建文件映射對象,方法是給CreateFileMapping函數(shù)的hFile參數(shù)傳遞INVALID_HANDLE_VALUE.注意,
            CreateFile()函數(shù)運行失敗也會返回這個參數(shù),因此一定要檢查CreateFile()的返回值。記住,文件函數(shù)運行失敗的可能性太大了。

            第三章:多個進程共享對象。

            堆棧:優(yōu)點:可以不考慮分配粒度和頁面邊界之類的問題,集中精力處理手頭的任務(wù),缺點是:分配和釋放內(nèi)存塊的速度比其他機制慢,并且無法直接控制物理存儲器的提交和回收。

            進程的默認堆棧是1MB,可以使用/HEAP鏈接開關(guān)調(diào)整大小,DLL沒有相關(guān)的堆棧。

            堆棧的問題在于:很多windows函數(shù)要使用臨時內(nèi)存塊,進程的多個線程要分配內(nèi)存塊,這些內(nèi)存都是在默認堆棧上分配的,但規(guī)定時間內(nèi),每次只能由一個線程能夠分配和釋放默認堆棧的內(nèi)存塊,其他想要處理內(nèi)存塊的線程必須等待。這種方法對速度又影響。可以為進程的線程創(chuàng)建輔助堆棧,但windows函數(shù)只能使用默認堆棧。

            獲取進程默認堆棧句柄:
            HANDLE GetProcessHeap();

            創(chuàng)建輔助堆棧的理由
            1 保護組件:
            多個組件的數(shù)據(jù)混合交叉的存放在一塊內(nèi)存里,那么一個組件的錯誤操作很容易影響到另外一個組件。而要定位錯誤的來源將十分困難。
            2 更有效的內(nèi)存管理
            通過在堆棧中分配同樣大小的對象,可以更加有效的管理內(nèi)存,減少內(nèi)存碎片。
            3 進行本地訪問:
            將同種數(shù)據(jù)集中到一定的內(nèi)存塊,可以在操作的時候訪問較少的頁面,這就減少了RAM和硬盤對換的可能.
            4 減少線程同步的開銷:
            通過告訴系統(tǒng)只有一個線程使用堆棧(創(chuàng)建堆棧時使用HEAP_NO_SERIALIZE標志給fdwOptions),可以避免堆棧函數(shù)執(zhí)行額外的用于保證堆棧安全性的代碼,提高效率,但此時用戶必須自己維護線程的安全性,系統(tǒng)不再對此負責(zé)。
            5 迅速釋放堆棧。
            因為數(shù)據(jù)單一,因此釋放的時候只要釋放堆棧即可,不必顯示的釋放每個內(nèi)存塊。

            創(chuàng)建輔助堆棧:
            HANDLE HeapCreate(
            DWORD fdwOptions,
            SIZE_T dwInitialSize,
            SIZE_T dwMaximumSize);

            從堆棧中分配內(nèi)存:
            PVOID HeapAlloc(
            HANDLE hHeap,
            DWORD fdwFlags,
            SIZE_T dwBytes);注意:當分配超過(1MB)內(nèi)存塊的時候,最好使用VirtualAlloc();

            改變內(nèi)存塊的大小:
            PVOID HeapReAlloc(
            HANDLE hHeap,
            DWORD fdwFlags,
            PVOID pvMem,
            SIZE_T dwBytes);

            檢索內(nèi)存塊的大小:
            SIZE_T HeapSize(
            HANDLE hHeap,
            DWORD fdwFlags,
            LPVOID pvMem);

            釋放內(nèi)存塊:
            BOOL HeapFree(
            HANDLE hHeap,
            DWORD fdwFlags,
            PVOID pvMem);

            撤銷堆棧:
            BOOL HeapDestroy(HANDLE hHeap);

            使用輔助堆棧的方法:重載對象的new操作符,在輔助堆上分配內(nèi)存,并給對象添加一個靜態(tài)變量用于保存堆句柄。

            其它堆棧函數(shù):
            獲取進程中所有堆棧得句柄:
            DWORD GetProcessHeaps(DWORD dwNumHeaps,PHANDLE pHeaps);
            驗證堆棧完整性:
            BOOL HeapValidate(
            HANDLE hHeap,
            DWORD fdwFlags,
            LPCVOID pvMem);
            合并地址中的空閑塊
            UINT HeapCompact(
            HANDLE hHeap,
            DWORD fdwFlags);

            BOOL HeapLock(HANDLE hHeap);
            BOOL HeapUnlock(HANDLE

            遍歷堆棧:
            BOOL HeapWalk(
            HANDLE hHeap,
            PProcess_HEAP_ENTRY pHeapEntry);

            各個dll也可以有自己的輸入表。

            如何編寫DLL:
            在DLL的頭文件中,有如下代碼:
            #ifdef MYLIB
            #else
            ??? #define MYLIB extern "C" __declspec(dllimport)???
            #endif
            在每個輸出變量和輸出函數(shù)的聲明前,用MYLIB修飾。
            在DLL的實現(xiàn)文件中,有如下代碼:
            #i nclude "windows.h"
            #define MYLIB extern "C" __declspec(dllexport)
            #i nclude "Mylib.h"

            其它的同編寫普通C++程序完全相同。 "C" 表示按C方式鏈接和調(diào)用函數(shù)。C++編譯器缺省按照__stdcall方式編譯和調(diào)用,這種方式會改變函數(shù)的內(nèi)部名字。此處如果把"C"都去掉也可以,但C程序?qū)o法調(diào)用。另外,使用GetProcAddress函數(shù)時也會發(fā)生困難,因為
            編譯程序已經(jīng)把函數(shù)名字改變了,無法用原來的名字得到函數(shù)地址。(核心編程說的不明白,沒想到這本書錯誤這么多)
            發(fā)行的時候,將頭文件、.lib文件和DLL文件給用戶就可以了。lib文件的作用是說明了頭文件中函數(shù)所在的DLL文件,如果沒有l(wèi)ib文件,編譯器將在鏈接過程中提示錯誤:unresolved external symbol 函數(shù)名。
            事實上,調(diào)用DLL有兩種方式,第一種是比較常用,即包含DLL的頭文件,并在鏈接的時候?qū)討B(tài)鏈接庫同exe文件像連接,建立輸入表。這個時候需要.lib文件。第二種方法exe文件中沒有輸入表,程序使用LoadLibrary(Ex)和GetProcAddress()顯式的加載DLL文件(卸載用FreeLibrary()),這個時候不需要.lib文件。
            HINSTANCE LoadLibrary(PCTSTR pszDLLpathName);
            HINSTANCE LoadLibraryEx(PCTSTR pszDLLpathName,NULL,0);

            兩次調(diào)用LoardLibrary并不會裝載兩次dll文件,只是將dll映射進進程的地址空間。系統(tǒng)會自動為每個進程維護一個dll的計數(shù)。FreeLiabray會使計數(shù)減一,如果計數(shù)為0,系統(tǒng)就會將dll從進程的地址空間卸載。


            HINSTANCE GetModuleHandle(PCTSTR pszModuleName);//確定dll是否已經(jīng)被映射進地址空間。
            HINSTANCE hinstDll=GetModuleHandle("MyLib");
            if(hinstDll==NULL)
            {
            ??? hinstDll=LoadLibrary("MyLib");
            }

            DWORD GetModuleFileName(
            ??? HINSTANCE hinstModule,
            ??? PTSTR pszPathName,
            ??? DWORD cchPath
            }
            可以獲得某個模塊(.exe或者dll)的全路徑名。

            幾個函數(shù)的用法:(注意GetProcAddress()函數(shù)的用法,如何定義和使用一個函數(shù)指針)
            typedef int (*MYPROC)(int,int);

            int main()
            {
            ?HINSTANCE t;
            ?t=LoadLibraryEx(TEXT("tt.dll"),NULL,0);
            ?if(t)
            ?{
            ??cout<<TEXT("load success")<<endl;

            ?}
            ?HINSTANCE hinstDll=GetModuleHandle("tt.dll");
            ?if(hinstDll==NULL)
            ?{
            ??cout<<TEXT("first load failed")<<endl;
            ??hinstDll=LoadLibrary("MyLib");
            ?}
            ?size_t sz=100;
            ?PTCHAR str=new TCHAR[sz];
            ?GetModuleFileName(t,str,sz);
            ?cout<<str<<endl;
            ?delete str;
            ?MYPROC add=NULL;
            ?add=(MYPROC)GetProcAddress(t,"add");
            ??? if(NULL!=add)
            ??? {
            ??cout<<(*add)(1,2)<<endl;
            ?}
            ?FreeLibrary(t);

            ?return 0;
            }


            UNICODE
            ANSI/UNICODE通用的定義方法(轉(zhuǎn)換只需要在編譯的時候使用_UNICODE和UNICODE):
            TCHAR _TEXT("success") PTSTR PCTSTR _tcscpy(),_tcscat();
            使用BYTE PBYTE定義字節(jié),字節(jié)指針和數(shù)據(jù)緩沖。
            傳遞給函數(shù)的緩存大小:sizeof(szBuffer)/sizeof(TCHAR)
            給字符串分配內(nèi)存:malloc(nCharacters*sizeof(TCHAR));
            其它的字符串函數(shù):
            PTSTR CharLower(PTSTR pszString);
            PTSTR CharUpper(PTSTR pszString);
            轉(zhuǎn)換單個字符:
            TCHAR c=CharLower((PTSTR)szString[0]);
            轉(zhuǎn)換緩存中的字符串(不必以0結(jié)尾):
            DWORD CharLowerBuff(
            PTSTR pszString,
            DWORD cchString);
            DWORD CharUpperBuff(
            PTSTR pszString,
            DWORD cchString);

            BOOL IsCharAlpha(TCHAR ch);
            BOOL IsCharAlpahNumeric(TCHAR ch);
            BOOL IsCharLower(TCHAR ch);
            BOOL IsCharUpper(TCHAR ch);

            線程本地存儲(TLS):為進程的每個線程存儲私有數(shù)據(jù)。用于那些一次傳遞參數(shù)后多次調(diào)用的函數(shù)(函數(shù)會保存上次調(diào)用的數(shù)據(jù))。
            實現(xiàn)方法:進程中有一個位標志樹組(win2000的這個數(shù)組大小超過1000)。在每個線程中有一個對應(yīng)的PVOID數(shù)組。通過設(shè)定位標志樹組的某個位來分配每個線程中的PVOID數(shù)組得相應(yīng)單元。函數(shù)需要每次檢索線程的PVOID數(shù)組,獲得該線程的相應(yīng)數(shù)據(jù)。

            DWORD TlsAlloc();? //為每個線程分配一個空的PVOID數(shù)組單元。

            BOOL TlsSetValue(? //線程設(shè)定自己的PVOID數(shù)組單元。
            DWORD dwTlsIndex,
            PVOID pvTlsValue);

            PVOID TlsGetValue(
            DWORD dwTlsIndex);? //檢索PVOID數(shù)組。

            BOOL TLSFree(
            DWORD dwTlsIndex);? //釋放PVOID數(shù)組單元

            靜態(tài)TLS:__declspec(thread) DWORD gt_dwStartTime=0;//只能修飾全局或者靜態(tài)變量。

            DLL掛接(進程注入):讓自己的DLL插入到其他進程的地址空間。

            1 使用注冊表插入DLL
            HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
            將你的DLL路徑放入這個關(guān)鍵字下面。當User32.dll被映射到進程中的時候,它會加在這個關(guān)鍵字下的每個庫。
            注意:(1)對win98無效
            ????? (2)由于加載事間比較早,你的DLL可能無法調(diào)用kernel32以外的dll.
            ?????? (3) 如果進程沒有使用user32.dll,這個方法無效。
            ?????? (4) 需要重新啟動。
            ????? (5)user32不會檢查每個庫是否加載成功。
            2 使用windows鉤子
            HOOK hHook=SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hinstDll,0);
            BOOL UnhookWindowsHookEx(HHOOK hhook);
            具體過程如下:
            ????? (1)進程B的一個線程準備發(fā)送消息給一個窗口。
            ????? (2)系統(tǒng)察看線程上是否已經(jīng)安裝了WH_GETMESSAGE鉤子。
            ????? (3)系統(tǒng)察看GetMsgProc的DLL是否已經(jīng)映射到了進程B的地址空間,如果沒有,系統(tǒng)將把DLL映射到B的地址空間,并自動增加引用計數(shù)。
            ????? (4)調(diào)用GetMsgProc函數(shù),返回時,系統(tǒng)會自動為DLL的引用計數(shù)減一。

            3 使用遠程線程來插入DLL
            ????? (1)使用VirtualAllocEx,分配遠程進程的地址空間的內(nèi)存。
            ????? (2)使用WriteProcessMemory,將Dll的路徑名拷貝到第一個步驟中已經(jīng)分配的內(nèi)存中。
            ????? (3)使用GetProcAddress,獲得LoadLibrary的實際地址。
            ????? (4)使用CreateRemoteThread,在遠程進程中創(chuàng)建一個線程。
            ????? 退出:?
            ????? (5)使用VirtualFreeEx,釋放內(nèi)存
            ????? (6)使用GetProcAddress,獲得FreeLiabary的地址。
            ????? (7)使用CreateRemoteThread,在遠程進程中創(chuàng)建一個線程,調(diào)用FreeLiabary函數(shù)。
            4 使用特洛伊DLL插入
            ? 替換dll.
            5 將DLL作為調(diào)試程序插入
            6 win98內(nèi)存映射文件,creatprocess

            結(jié)構(gòu)化異常處理:
            結(jié)束處理程序:__try{} __finally{}
            除非__try執(zhí)行中進程或者線程結(jié)束,否則總會執(zhí)行__finally,并且__finally中的return會替代__try中的return;好的習(xí)慣是將return ,continue,break,goto語句拿到結(jié)構(gòu)化異常處理語句外面,可以節(jié)省開銷。將__try中的return 換成__leave,可以節(jié)省開銷。在__finally總確定時正常進入還是展開進入:
            BOOL AbnormalTermination();//正常進入返回FALSE,局部展開或者全局展開返回TRUE;

            異常處理程序:__try{}__exception(異常過濾表達式){}

            EXCEPTION_EXECUTE_HANDLE
            表示處理異常,處理后轉(zhuǎn)到exception塊后面的代碼繼續(xù)執(zhí)行。
            EXCEPTION_CONTINUE_EXECUTION
            EXCEPTION_CONTINUE_SEARCH

            可以對異常過濾表達式進行硬編碼,也可以用一個調(diào)用一個函數(shù)來決定過濾表達式,函數(shù)的返回值是LONG.例如,可以進行一定處理,然后返回EXCEPTION_CONTINUE_EXECUTION,再次執(zhí)行出錯語句。但可能再次出錯,因此這種方法必須小心,防止生成死循環(huán)。

            DWORD GetExceptionCode() 可以獲得異常種類。它只能在__except后的括號或者異常處理程序中調(diào)用。

            發(fā)生異常后,操作系統(tǒng)會像引起異常的線程的棧里壓入三個結(jié)構(gòu):EXCEPTION_RECORD CONTEXT EXCEPTION_POINTERS,其中第三個結(jié)構(gòu)包含兩個成員指針,分別指向前兩個結(jié)構(gòu),使用函數(shù)可以獲得第三個結(jié)構(gòu)的指針:
            PEXCEPTION_POINTERS GetExceptionInformation();//僅可以在異常過濾器中調(diào)用,既__exception后面的小括號。

            逗號表達式:從左到右對所有的表達式求值,并返回最有面的表達式的值。

            引發(fā)軟件異常:
            VOID RaiseException(
            DWORD dwExceptionCode,
            DWORD dwExceptionFlags,
            DWORD nNumberOfArguments,
            CONST ULONG_PTR *pArguments);

            缺省調(diào)試器所在注冊表:
            HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug? Debugger
            win98是存放在win.ini里

            調(diào)試器掛接到被調(diào)試進程
            BOOL DebugActiveProcess(DWORD dwProcessID);


            while(*str++!='\0');
            應(yīng)該注意的是在不滿足條件后,str仍然會自加1。

            位操作符>>和<<不會做循環(huán)位移,即不會把移出的位放到另一頭。

            多態(tài)性和動態(tài)聯(lián)編的實現(xiàn)過程分析

              一、基礎(chǔ):

              1、多態(tài)性:使用基礎(chǔ)類的指針動態(tài)調(diào)用其派生類中函數(shù)的特性。

              2、動態(tài)聯(lián)編:在運行階段,才將函數(shù)的調(diào)用與對應(yīng)的函數(shù)體進行連接的方式,又叫運行時聯(lián)編或晚捆綁。

              二、過程描述:

              1、編譯器發(fā)現(xiàn)一個類中有虛函數(shù),編譯器會立即為此類生成虛擬函數(shù)表 vtable(后面有對vtable的分析)。虛擬函數(shù)表的各表項為指向?qū)?yīng)虛擬函數(shù)的指針。

              2、編譯器在此類中隱含插入一個指針vptr(對vc編譯器來說,它插在類的第一個位置上)。

              有一個辦法可以讓你感知這個隱含指針的存在,雖然你不能在類中直接看到它,但你可以比較一下含有虛擬函數(shù)時的類的尺寸和沒有虛擬函數(shù)時的類的尺寸,你能夠發(fā)現(xiàn),這個指針確實存在。

              3、在調(diào)用此類的構(gòu)造函數(shù)時,在類的構(gòu)造函數(shù)中,編譯器會隱含執(zhí)行vptr與vtable的關(guān)聯(lián)代碼,將vptr指向?qū)?yīng)的vtable。這就將類與此類的vtable聯(lián)系了起來。

              4、在調(diào)用類的構(gòu)造函數(shù)時,指向基礎(chǔ)類的指針此時已經(jīng)變成指向具體的類的this指針,這樣依靠此this指針即可得到正確的vtable,從而實現(xiàn)了多態(tài)性。在此時才能真正與函數(shù)體進行連接,這就是動態(tài)聯(lián)編。

            定義純虛函數(shù)方法:virtual returntype function()= 0;

            所有的類型都可以用new動態(tài)創(chuàng)建,包括類,結(jié)構(gòu),內(nèi)置數(shù)據(jù)類型。

            exit()函數(shù)包含在"cstdlib"中

            泛型編程,使用STL庫
            總共有近75個泛型算法

            所有容器的共通操作:
            == != = empty() size() clear(),begin(),end(),以及insert和erase,不過后者隨容器的的不同而不同

            序列式容器:
            vector(數(shù)組):插入和刪除的效率較低,但存取效率高。
            list(雙向鏈表):與前者相反,插入和刪除的效率較高,但存取效率低。每個元素包含三個字段:value back front.
            deque(隊列):在前端和末尾操作效率高。

            生成序列式容器的五種方法:
            1 產(chǎn)生空的容器:
            list<string> slist;
            vector<int> vtor;
            2 產(chǎn)生特定大小的容器,容器中的每個元素都以其默認值為初值(發(fā)現(xiàn)VC中的int double等沒有默認值)。
            list<int> ilist(1024);
            vector<string> svec(24);
            3 產(chǎn)生特定大小的容器,并為每個元素指定初值:
            list<int ilist(1024,0);
            vector<string> svec(24,"default");
            4 通過一對迭代器產(chǎn)生容器,這對迭代器用來表示數(shù)組作為初值的區(qū)間:
            int ia[10]={1,2,3,4,5,6,7,8,9,0};
            vector<int>? iv(ia+2,ia+8);
            5 復(fù)制某個現(xiàn)有的容器的值:
            vector<int> ivec1;
            //填充ivec1;
            vector<int> ivec2(ivec1);

            有6個方法用于操作開始和末尾的元素:push_front() pop_front() push_back() pop_back(),由于pop操作僅刪除元素而不返回元素,因此還需要front() back()方法取開始和末尾的元素,另外,vector不包括push_front() pop_front方法,很顯然,無法實現(xiàn)。

            intert的四種變形:
            iterator insert(iterator position,elemType value):將value插到position前。返回值指向被插入的元素。
            void insert(iterator position,int count,elemType value):在position前插入count個元素,每個元素都是value.
            void insert(iterator1 position,iterator2 first,iterator2 last):將first,last之間的元素插到position前.
            iterator insert( iterator position):在position前插入元素,初值為所屬類型的默認值。

            erase的兩種變形:
            1? iterator erase(iterator posit):刪除posit指向的元素。
            list<string>::iterator it=find(slist.begin(),slist,end(),str);
            slist.erase(it);
            2? iterator erase(iterator first,iterator last):刪除first,last間的元素。

            list不支持iterator的偏移運算

            對于常值容器,使用常迭代器:
            const vector<string> cs_vec;
            vector<string::const_iterator iter_cs_vec.begin();

            iterator可以當作指針用,可以用*取內(nèi)容,也可以用->調(diào)用對象的成員。

            使用泛型算法
            #i nclude <algorithm>

            find():線性搜索無序集合
            binary_search():二分搜索有序集合。
            count():返回元素個數(shù)。
            search():搜索序列,如果存在返回的iterator指向序列首部,否則指向容器末尾。
            max_element(begin,end):返回區(qū)間內(nèi)的最大值。
            copy(begin,end,begin):元素復(fù)制。
            sort(begin,end):排序。

            function objects:#i nclude <functional>
            算術(shù)運算:
            plus<type> minus<type> negate<type> multiplies<type> divides<type> modules<type>
            關(guān)系運算:
            less<type> less equal<type> greater<type greater equal<type> equal_to<type> not_equal_to<type>
            邏輯運算:
            logical_and<type> logical_or<type> logical_not<type>

            adapter:適配器。
            bind1st:將數(shù)值綁定到function object的第一個參數(shù)。
            bind2nd:將數(shù)值綁定到function object的第二個參數(shù)。

            使用map:
            #i nclude <map>
            #i nclude <string>
            map<string,int> words;

            words["vermeer"]=1;

            map<string,int>::iterator it=words.begin();
            for(;it!=words.end();++it)
            cout<<"key:"<<it->first<<"value:"<<it->second<<endl;

            查找map元素的方法:
            words.find("vermeer");//返回iterator,指向找到的元素,找不到返回end();
            還可以:
            if(words.count(search_word))
            count=words[search_word];

            使用set:
            #i nclude <set>
            #i nclude <string>
            set<string> word_exclusion;
            //判斷是否存在某個元素
            if(word_exclusion.count(tword))
            //默認情況下,所有元素按less-than運算排列

            //加入元素
            iset.insert(ival);
            iset.insert(vec.begin(),vec.end());

            與set相關(guān)的算法
            set_intersection() set_union() set_difference() set_symmetric_difference()

            使用insertion adapters:
            #i nclude <iterator>
            back_inserter()
            inserter()
            front_inserter()

            使用STL通常會有很多警告,為了避免在調(diào)試模式(debug mode)出現(xiàn)惱人的警告,使用下面的編譯器命令:

            #pragma warning(disable: 4786)

            strncpy(dest,source,count) if(count〈=strlen(source)),那么null結(jié)尾不會被加在dest的尾部,如果count>strlen(source),那么不足的部分會用null填充。


            windows內(nèi)存是由高地址向底地址分配的,但變量的存儲是從底地址到高地址的,如INT類型的四個字節(jié),數(shù)組的每個元素。
            ?
            內(nèi)存復(fù)制的時候不能用字符串拷貝函數(shù),因為即使使用strncpy指定了復(fù)制的長度,拷貝函數(shù)也會遇到'\0'自動終止,要使用MEMSET。

            由于對齊的關(guān)系,下面兩個結(jié)構(gòu)使用sizeof,前者是12,后者是16。
            struct DNSAnswer
            {
            ?unsigned short name;
            ?unsigned short type;
            ?unsigned short cla;
            ?unsigned short length;
            ?unsigned int?? ttl;
            };
            struct DNSAnswer
            {
            ?unsigned short name;
            ?unsigned short type;
            ?unsigned short cla;
            ?unsigned int?? ttl;
            ??????? unsigned short length;
            };

            子類可以使用父類的保護成員,而友元比子類的權(quán)限還大,可以使用類的私有和保護成員。

            在內(nèi)存分配失敗的情況下,系統(tǒng)只有在出錯處理函數(shù)為空的情況下,才會拋出異常:std::bad_alloc(),否則會反復(fù)調(diào)用處理函數(shù)并再次嘗試分配內(nèi)存。

            如果重載了NEW,那么在繼承的時候要小心,如果子類沒有覆蓋NEW,那么它會去使用父類的NEW ,因此應(yīng)該在new,delete中做檢查
            if (size != sizeof(base))???????????? // 如果數(shù)量“錯誤”,讓標準operator new,base為類名
            ??? return ::operator new(size);??????? // 去處理這個請求

            ? if (size != sizeof(base)) {????? // 如果size"錯誤",
            ??? ::operator delete(rawmemory);? // 讓標準operator來處理請求
            ??? return;???????????????????????
            ? }

            c++標準規(guī)定,要支持0內(nèi)存請求(分配一個字節(jié)),并且可以刪除NULL指針(直接返回)。

            在創(chuàng)建線程的時候,傳遞的變量一定要是全局或者靜態(tài)的變量,因為傳遞的是變量的地址,如果是局部變量地址很快就會失效。

            主線程退出后,其子線程自動結(jié)束。

            智能指針:它可以避免內(nèi)存泄露,因為智能指針是在棧上創(chuàng)建的;還可以避免堆上內(nèi)存的重復(fù)釋放錯誤,因為它保證只有一個指針擁有這塊內(nèi)存的所有權(quán)。

            日韩一区二区三区视频久久| 国产一区二区精品久久岳| 9191精品国产免费久久| 亚洲精品tv久久久久久久久 | 久久精品国产精品亚洲毛片| 久久人人爽人人精品视频| 香蕉久久夜色精品国产小说| 久久久久夜夜夜精品国产| 久久精品国产久精国产| 天天综合久久久网| 久久狠狠一本精品综合网| 久久久网中文字幕| 婷婷国产天堂久久综合五月| 久久综合精品国产一区二区三区| 色综合合久久天天给综看| 久久国产精品无| 婷婷久久久亚洲欧洲日产国码AV | 久久久精品久久久久久 | 思思久久99热只有频精品66| 久久青青草原精品国产不卡| 色青青草原桃花久久综合| 久久久一本精品99久久精品66| 97久久久精品综合88久久| 丁香五月综合久久激情| 日本亚洲色大成网站WWW久久 | 久久99国产精品一区二区| 精品久久久久久无码中文字幕| 伊人久久大香线蕉无码麻豆| 久久午夜无码鲁丝片| 久久99国产精品成人欧美| 精品国产乱码久久久久久人妻| 国产精品一区二区久久国产| 精品无码久久久久久久久久| 精品一二三区久久aaa片| 一级做a爰片久久毛片人呢| 久久无码AV一区二区三区| 久久久中文字幕| 2021国内精品久久久久久影院| 久久永久免费人妻精品下载| 久久男人中文字幕资源站| 伊人丁香狠狠色综合久久|