對這個兩個常見的windows下的函數學習了一下:
//最簡單的建立多線程執行個體
#include <stdio.h>
#include <windows.h>
//子線程函數
DWORD WINAPI ThreadFun(LPVOID pM)
{
printf("子線程的線程ID号為:%d\n子線程輸出Hello World\n", GetCurrentThreadId());
return 0;
}
//主函數,所謂主函數其實就是主線程執行的函數。
int main()
{
printf(" 最簡單的建立多線程執行個體\n");
printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");
HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
WaitForSingleObject(handle, INFINITE);
return 0;
}
第一個 CreateThread
函數功能:建立線程
函數原型:
HANDLE WINAPI CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
函數說明:
第一個參數表示線程核心對象的安全屬性,一般傳入NULL表示使用預設設定。
第二個參數表示線程棧空間大小。傳入0表示使用預設大小(1MB)。
第三個參數表示新線程所執行的線程函數位址,多個線程可以使用同一個函數位址。
第四個參數是傳給線程函數的參數。
第五個參數指定額外的标志來控制線程的建立,為0表示線程建立之後立即就可以進行排程,如果為CREATE_SUSPENDED則表示線程建立後暫停運作,這樣它就無法排程,直到調用ResumeThread()。
第六個參數将傳回線程的ID号,傳入NULL表示不需要傳回該線程ID号。
函數傳回值:
成功傳回新線程的句柄,失敗傳回NULL。
第二個 WaitForSingleObject
函數功能:等待函數 – 使線程進入等待狀态,直到指定的核心對象被觸發。
函數原形:
DWORD WINAPI WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
第一個參數為要等待的核心對象。
第二個參數為最長等待的時間,以毫秒為機關,如傳入5000就表示5秒,傳入0就立即傳回,傳入INFINITE表示無限等待。
因為線程的句柄線上程運作時是未觸發的,線程結束運作,句柄處于觸發狀态。是以可以用WaitForSingleObject()來等待一個線程結束運作。
在指定的時間内對象被觸發,函數傳回WAIT_OBJECT_0。超過最長等待時間對象仍未被觸發傳回WAIT_TIMEOUT。傳入參數有錯誤将傳回WAIT_FAILED
CreateThread()函數是Windows提供的API接口,在C/C++語言另有一個建立線程的函數_beginthreadex(),在很多書上(包括《Windows核心程式設計》)提到過盡量使用_beginthreadex()來代替使用CreateThread(),
原因:_beginthreadex()函數在建立新線程時會配置設定并初始化一個_tiddata塊。這個_tiddata塊自然是用來存放一些需要線程獨享的資料。事實上新線程運作時會首先将_tiddata塊與自己進一步關聯起來。然後新線程調用标準C運作庫函數如strtok()時就會先取得_tiddata塊的位址再将需要保護的資料存入_tiddata塊中。這樣每個線程就隻會通路和修改自己的資料而不會去篡改其它線程的資料了。是以,如果在代碼中有使用标準C運作庫中的函數時,盡量使用_beginthreadex()來代替CreateThread()
getbuffer是為了讓你使用CString類中,儲存字元串緩沖區的那塊指針.
至于releasebuffer,在MSDN中有這樣一句話.
If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CString member functions.
在對GetBuffer傳回的指針使用之後需要調用ReleaseBuffer,這樣才能使用其他Cstring的operations。否則會發生錯誤.
GetBuffer(0)傳回的是指向CString對象所構造的字串指針,為GetBuffer(0)由系統自動計算字串所要的空間長度,但要求是規則的含\0字串,否則得自己給出長度,如str.GetBuffer(20)。
LPTSTR GetBuffer( int nMinBufLength ) 這個函數是CString 的一個比較實用的函數,請看如下示例:
GetBuffer(int nMinBufLength);的參數問題一直比較困擾人,網站的資料還像也不是太好給的,請看msdn解釋
Parameters
nMinBufLength
The minimum size of the character buffer in characters. This value does not include space for a null terminator.
得到buffer的最小長度,當然這是由我們自己設定的一個參數,其原型定義如下:
LPTSTR CString::GetBuffer(int nMinBufLength)
{
ASSERT(nMinBufLength >= 0);
if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
{
#ifdef _DEBUG
// give a warning in case locked string becomes unlocked
if (GetData() != _afxDataNil && GetData()->nRefs < 0)
TRACE0("Warning: GetBuffer on locked CString creates unlocked CString!/n");
#endif
// we have to grow the buffer
CStringData* pOldData = GetData();
int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
if (nMinBufLength < nOldLen)
nMinBufLength = nOldLen;
AllocBuffer(nMinBufLength);
memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
GetData()->nDataLength = nOldLen;
CString::Release(pOldData);
}
ASSERT(GetData()->nRefs <= 1);
// return a pointer to the character storage for this string
ASSERT(m_pchData != NULL);
return m_pchData;
}
上面的代碼已經比較清楚了,當設定的長度小于原字元串長度時,nMinBufLength = nOldLen,然後配置設定相應的記憶體,當你設定的長度大于原字元串本身的長度時就要配置設定一塊比較大的空間出來,這時你可以實作字元串對接的操作。
GetBuffer()主要作用是将字元串的緩沖區長度鎖定,releaseBuffer則是解除鎖定,使得CString對象在以後的代碼中繼續可以實作長度自适應增長的功能。
CString ::GetBuffer有兩個重載版本:
LPTSTR GetBuffer( );LPTSTR GetBuffer(int nMinBufferLength);
在第二個版本中,當設定的長度小于原字元串長度時,nMinBufLength = nOldLen,該參數會被忽
略,不配置設定記憶體,指向原CString;當設定的長度大于原字元串本身的長度時就要重新配置設定(reallocate)一塊比較大的空間出來。而調用第一個版本時,應如通過傳入0來調用第二個版本一樣。
是否需要在GetBufer後面調用ReleaseBuffer(),是根據你的後面的程式是否需要繼續使用該字元串變量,并且是否動态改變其長度而定的。如果你GetBuffer以後程式自函數就退出,局部變量都不存在了,調用不調用ReleaseBuffer沒什麼意義了。
這是一個非常容易被用錯的函數,主要可能是由于大家對它的功能不太了解。其實點破的話,也不是那麼深奧。
GetBuffer(int size)是用來傳回一個你所指定大小可寫記憶體的成員方法。它和被重載的操作符LPCTSTR還是有點本質差別的,LPCTSTR是直接傳回一個隻讀記憶體的指針,而GetBuffer則是傳回一個可以供調用者寫入的記憶體,并且,你可以給定大小。下面是個簡單的,但也是非常典型的例子:
int readFile(CString& str, const CString& strPathName)
{
FILE* fp = fopen(strPathName, "r"); // 打開檔案
fseek(fp, 0, SEEK_END);
int nLen = ftell(fp); // 獲得檔案長度
fseek(fp, 0, SEEK_SET); // 重置讀指針
char* psz = str.GetBuffer(nLen);
fread(psz, sizeof(char), nLen, fp); //讀檔案内容
str.ReleaseBuffer(); //千萬不能缺少
fclose(fp);
}
上面的函數是GetBuffer函數最典型的用法了,其實它就相當于申請一塊nLen大小的記憶體,隻不過,這塊記憶體是被引用在CString對象的内部而已,這是非常有效的一種用法,如果不直接用GetBuffer函數來申請的話,那麼你必須用new操作符(或者malloc()函數)在CString的外部申請,然後再将申請的記憶體拷貝到CString對象中,顯然這是一個非常備援的操作,會使你函數的效率大大下降。
ReleaseBuffer函數是用來告訴CString對象,你的GetBuffer所引用的記憶體已經使用完畢,現在必須對它進行封口,否則 CString将不會知道它現在所包含的字元串的長度,是以在使用完GetBuffer之後,必須立即調用ReleaseBuffer函數重置 CString的内部屬性,其實也就是頭部資訊。
補充一下:
GetBuffer說白了就兩個功能:
1:就是将CString裡面的記憶體交到外部一個來處理,外部可以直接修改它的内容。
2:重新修改CString的記憶體大小,這個數值不包含null結尾符。
另一個典型的用法:就是将CString裡面的内容變為int或long型,需要先擷取裡面的記憶體指針。這樣就可以先GetBuffer(記憶體大小)友善直接轉換。
如果在外部修改了CString裡面的内容,在重新使用CString之前,需調用ReleaseBuffer()也就是說,ReleaseBuffer不需要每次都調用。
MSDN原文:
If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CSimpleStringT member methods.
The buffer memory is automatically freed when the CSimpleStringT object is destroyed.
If you keep track of the string length yourself, you should not append the terminating null character. You must, however, specify the final string length when you release the buffer with ReleaseBuffer. If you do append a terminating null character, you should pass –1 (the default) for the length toReleaseBuffer, and ReleaseBuffer will perform a strlen on the buffer to determine its length.
C/C++基本文法學習
STL
C++ primer