一、轉載自: http://www.cnblogs.com/chuncn/archive/2009/03/08/1406096.html
CreateThread是Windows的API函數(SDK函數的標準形式,直截了當的建立方式,任何場合都可以使用),提供作業系統層級的建立線程的操作,且僅限於工作者線程。不調用MFC和RTL的函數時,可以用CreateThread,其它情況不要輕易。在使用的過程中要考慮到進程的同步與互斥的關係(防止死結)。線程函數定義為:DWORD WINAPI _yourThreadFun(LPVOID pParameter)。但它沒有考慮:
(1)C Runtime中需要對多線程進行紀錄和初始化,以保證C函數庫工作正常(典型的例子是strtok函數)。
(2)MFC也需要知道新線程的建立,也需要做一些初始化工作(當然,如果沒用MFC就沒事了)。
AfxBeginThread:MFC中線程建立的MFC函數,首先建立了相應的CWinThread對象,然後調用CWinThread::CreateThread, 在CWinThread::CreateThread中,完成了對線程對象的初始化工作,然後,調用_beginthreadex(AfxBeginThread相比較更為安全)建立線程。它簡化了操作或讓線程能夠響應訊息,即可用於介面線程,也可以用於工作者線程,但要注意不要在一個MFC程式中使用_beginthreadex()或CreateThread()。線程函數定義為:UINT _yourThreadFun(LPVOID pParam)
_beginthreadex:MS對C Runtime庫的擴充SDK函數,首先針對C Runtime庫做了一些初始化的工作,以保證C Runtime庫工作正常。然後,調用CreateThread真正建立線程。 僅使用Runtime Library時,可以用_BegingThread。
uintptr_t _beginthread(
void( *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
_beginthreadex( NULL, 0, threadProc, &pagram, 0,
(unsigned int *) idThread );
小節:實際上,這三個函數之間存在一定的調用關係,第一個純粹一些,後兩個完成自己相應的工作之後,調用前者實現線程的建立。其中CreateThread是由作業系統提供的介面,而AfxBeginThread和_BeginThread則是編譯器對它的封裝。
小節:用_beginthreadex()、_endthreadex函數應該是最佳選擇,且都是C Run-time Library中的函數,函數的參數和資料類型都是C Run-time Library中的類型,這樣在啟動線程時就不需要進行Windows資料類型和C Run-time Library中的資料類型之間的轉化,從而,減低了線程啟動時的資源消耗和時間的消耗。但使用_beginthread,無法建立帶有安全屬性的新線程,無法建立暫停線程,也無法獲得 線程ID,_endthread的情況類似,它不帶參數,這意味這線程的結束代碼必須寫入程式碼為0。
小節:MFC也是C++類庫(只不過是Microsoft的C++類庫,不是標準的C++類庫),在MFC中也封裝了new和delete兩中運算子,所以用到new和delete的地方不一定非要使用_beginthreadex() 函數,用其他兩個函數都可以。
_beginthreadex和_beginthread在回調入口函數之前進行一些線程相關的CRT的初始化操作。
CRT的函數庫線上程出現之前就已經存在,所以原有的CRT不能真正支援線程,
這也導致了許多CRT的函數在多線程的情況下必須有特殊的支援,不能簡單的使用CreateThread就OK。
二、轉載自: http://www.cppblog.com/bidepan2023/archive/2007/10/31/35627.html
當你打算實現一個多線程(非MFC)程式,你會選擇一個單線程的CRT(C執行階段程式庫)嗎?如果你的回答是NO, 那麼會帶來另外一個問題,你選擇了CreateThread來建立一個線程嗎? 大多數人也許會立刻回答YES。可是很不幸,這是錯誤的選擇。
我先來說一下我的結論,待會告訴你為什麼。
如果要作多線程(非MFC)程式,在主線程以外的任何線程內
- 使用malloc(),free(),new
- 調用stdio.h或io.h,包括fopen(),open(),getchar(),write(),printf(),errno
- 使用浮點變數和浮點運算函數
- 調用那些使用靜態緩衝區的函數如: asctime(),strtok(),rand()等。
你就應該使用多線程的CRT並配合_beginthreadex(該函數只存在於多線程CRT), 其他情況下你可以使用單線程的CRT並配合CreateThread。
因為對產生的線程而言,_beginthreadex比之CreateThread會為上述操作多做額外的簿記工作,比如協助strtok()為每個線程準備一份緩衝區。
然而多線程程式極少情況不使用上述那些函數(比如記憶體配置或者io),所以與其每次都要思考是要使用_beginthreadex還是CreateThread,不如就一棍子敲定_beginthreadex。
當然你也許會藉助win32來處理記憶體配置和Io,這時候你確實可以以單線程crt配合CreateThread,因為io的重任已經從crt轉交給了win32。這時通常你應該使用HeapAlloc,HeapFree來處理記憶體配置,用CreateFile或者GetStdHandle來處理Io。
還有一點比較重要的是_beginthreadex傳回的雖然是個unsigned long,其實是個線程Handle(事實上_beginthreadex在內部就是調用了CreateThread),所以你應該用CloseHandle來結束他。千萬不要使用ExitThread()來退出_beginthreadex建立的線程,那樣會喪失釋放簿記資料的機會,應該使用_endthreadex.
三、轉載自:http://blog.csdn.net/idau7/archive/2007/08/25/1758712.aspx
這兩天剛好手頭有點事情跟線程相關, 剛好細細拜讀jjh先生所譯的win32線程大作, 有點不知所云, 起碼是被弄的一愣一愣的, 偏聽則暗, 果然如此, 只知其然而不知所以然, 恐怕過兩天還是會忘記的. 就當寫寫心得記錄了.
1. 已知windows下可以用如下方法建立線程.
1) CreadThread(…). API
2) _beginthread(…). CRT
3) _beginthreadex(…). CRT
4) AfxBeginThread(…). MFC
由於AfxBeginThread()同學勾搭MFC, 揚言誓死不分, 開除先.
_beginthreadex()和_beginthread()長的很像, 沒什麼直接血緣關係, 但都是CRT所提供的線程建立方式. 顯著區別在於參數和傳回值上.
2. _beginthread(…)與_beginthreadex(…)區別.
1) 參數區別.
2) 傳回值區別
_beginthread()返回-1表示失敗, 而_beginthreadex()返回0表示失敗
3) 實際過程區別.
3. _beginthreadex(…)與CreadThread(…)區別.
1) 參數區別.
兩者參數基本相同, 只是CreadThread()的參數是windows定義的win32資料類型, 而_beginthreadex()是標準C/C++的資料類型. 需要注意的是, CreateThread()的第三個參數函數指標是unsign long的, 而_beginthreadex()的第三個參數函數指標是unsign int的.
2) 傳回值區別.
CreateThread(), 返回的是建立的線程的HANDLE,
_beginthreadex(), 返回的一個是unsigned long. 需通過reinterpret_cast<HANDLE>或(HANDLE)來強制轉換.
3) 實際過程區別.
的
一般不建議直接調用CreateThread(), 除非可以非常確定
4. 選擇_beginthreadex()和CreateThread()的一般性規則.
不建議使用CreateThread(). 尤其當線程:
l 使用了malloc()/free(), new/delete的線程.
l 調用stdio.h或io.h中聲明的任何函數.
l 使用浮點變數.
5. 為什麼winCE上只能用CreateThread()?
我也不知道為什麼….
參考文獻:
1. MSJ(Mircsofts System Journal) July 1999
http://www.microsoft.com/msj/0799/Win32/Win320799.aspx
2. <Win32多線程程式設計>
3. <windows核心編程>. 6章.
4. oRbIt 的專欄. <CreateThread()和_beginthreadex()區別>.
http://blog.csdn.net/orbit/archive/2005/07/30/440118.aspx
向遠處看的專欄. <CreateThread()和_beginthreadex()區別>
http://blog.csdn.net/xuxinshao/archive/2005/09/14/480797.aspx
搞不清誰的原創了….兩位大仙都寫原創…那…那肯定有個是引用的啊…要不難道是異靈事件?
5. kind_li的專欄 kind_li 線程知識點.
http://blog.csdn.net/kind_li/archive/2003/04/03/10998.aspx
6. 運行時: 管理進程和線程
http://www-128.ibm.com/developerworks/cn/linux/sdk/rt/part7/index.html
7. MSDN, _beginthreadex()跟_beginthread()的區別.
http://msdn2.microsoft.com/en-us/library/kdzttdcb(VS.71).aspx
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/idau7/archive/2007/08/25/1758712.aspx
四、轉載自 http://820808.blog.51cto.com/328558/76160
五、來自msdn:
ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vccrt/html/0df64740-a978-4358-a88f-fb0702720091.htm
// The following example uses _beginthread and _endthread</p><p>// crt_BEGTHRD.C<br />// compile with: /MT /D "_X86_" /c<br />// processor: x86<br />#include <windows.h><br />#include <process.h> /* _beginthread, _endthread */<br />#include <stddef.h><br />#include <stdlib.h><br />#include <conio.h></p><p>void Bounce( void *ch );<br />void CheckKey( void *dummy );</p><p>/* GetRandom returns a random integer between min and max. */<br />#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))</p><p>BOOL repeat = TRUE; /* Global repeat flag and video variable */<br />HANDLE hStdOut; /* Handle for console window */<br />CONSOLE_SCREEN_BUFFER_INFO csbi; /* Console information structure */</p><p>int main()<br />{<br /> CHAR ch = 'A';</p><p> hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );</p><p> /* Get display screen's text row and column information. */<br /> GetConsoleScreenBufferInfo( hStdOut, &csbi );</p><p> /* Launch CheckKey thread to check for terminating keystroke. */<br /> _beginthread( CheckKey, 0, NULL );</p><p> /* Loop until CheckKey terminates program. */<br /> while( repeat )<br /> {<br /> /* On first loops, launch character threads. */<br /> _beginthread( Bounce, 0, (void *) (ch++) );</p><p> /* Wait one second between loops. */<br /> Sleep( 1000L );<br /> }<br />}</p><p>/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */<br />void CheckKey( void *dummy )<br />{<br /> _getch();<br /> repeat = 0; /* _endthread implied */</p><p>}</p><p>/* Bounce - Thread to create and and control a colored letter that moves<br /> * around on the screen.<br /> *<br /> * Params: ch - the letter to be moved<br /> */<br />void Bounce( void *ch )<br />{<br /> /* Generate letter and color attribute from thread argument. */<br /> char blankcell = 0x20;<br /> char blockcell = (char) ch;<br /> BOOL first = TRUE;<br /> COORD oldcoord, newcoord;<br /> DWORD result;</p><p> /* Seed random number generator and get initial location. */<br /> srand( _threadid );<br /> newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );<br /> newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );<br /> while( repeat )<br /> {<br /> /* Pause between loops. */<br /> Sleep( 100L );</p><p> /* Blank out our old position on the screen, and draw new letter. */<br /> if( first )<br /> first = FALSE;<br /> else<br /> WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );<br /> WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );</p><p> /* Increment the coordinate for next placement of the block. */<br /> oldcoord.X = newcoord.X;<br /> oldcoord.Y = newcoord.Y;<br /> newcoord.X += GetRandom( -1, 1 );<br /> newcoord.Y += GetRandom( -1, 1 );</p><p> /* Correct placement (and beep) if about to go off the screen. */<br /> if( newcoord.X < 0 )<br /> newcoord.X = 1;<br /> else if( newcoord.X == csbi.dwSize.X )<br /> newcoord.X = csbi.dwSize.X - 2;<br /> else if( newcoord.Y < 0 )<br /> newcoord.Y = 1;<br /> else if( newcoord.Y == csbi.dwSize.Y )<br /> newcoord.Y = csbi.dwSize.Y - 2;</p><p> /* If not at a screen border, continue, otherwise beep. */<br /> else<br /> continue;<br /> Beep( ((char) ch - 'A') * 100, 175 );<br /> }<br /> /* _endthread given to terminate */<br /> _endthread();<br />}
/*The following sample code demonstrates how you can use the thread handle returned by _beginthreadex with the synchronization API WaitForSingleObject. The main thread waits for the second thread to terminate before it continues. When the second thread calls _endthreadex, it causes its thread object to go to the signaled state. This allows the primary thread to continue running. This cannot be done with _beginthread and _endthread, because _endthread calls CloseHandle, destroying the thread object before it can be set to the signaled state.*/</p><p>// crt_begthrdex.cpp<br />// compile with: /MT<br />#include <windows.h><br />#include <stdio.h><br />#include <process.h></p><p>unsigned Counter;<br />unsigned __stdcall SecondThreadFunc( void* pArguments )<br />{<br /> printf( "In second thread.../n" );</p><p> while ( Counter < 1000000 )<br /> Counter++;</p><p> _endthreadex( 0 );<br /> return 0;<br />} </p><p>int main()<br />{<br /> HANDLE hThread;<br /> unsigned threadID;</p><p> printf( "Creating second thread.../n" );</p><p> // Create the second thread.<br /> hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );</p><p> // Wait until second thread terminates. If you comment out the line<br /> // below, Counter will not be correct because the thread has not<br /> // terminated, and Counter most likely has not been incremented to<br /> // 1000000 yet.<br /> WaitForSingleObject( hThread, INFINITE );<br /> printf( "Counter should be 1000000; it is-> %d/n", Counter );<br /> // Destroy the thread object.<br /> CloseHandle( hThread );<br />}
msdn :
ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.WIN32COM.v10.en/dllproc/base/creating_threads.htm
The CreateThread function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program code (for more information, see ThreadProc). This function takes a single parameter and returns a DWORD value. A process can have multiple threads simultaneously executing the same function. </p><p>/*<br />The following is a simple example that demonstrates how to create a new thread that executes the locally defined function, ThreadProc. The creating thread uses a dynamically allocated buffer to pass unique information to each instance of the thread function. It is the responsibility of the thread function to free the memory.</p><p>The calling thread uses the WaitForMultipleObjects function to persist until all worker threads have terminated. Note that if you were to close the handle to a worker thread before it terminated, this does not terminate the worker thread. However, the handle will be unavailable for use in subsequent function calls.*/</p><p>#include <windows.h><br />#include <strsafe.h></p><p>#define MAX_THREADS 3<br />#define BUF_SIZE 255</p><p>typedef struct _MyData {<br /> int val1;<br /> int val2;<br />} MYDATA, *PMYDATA;</p><p>DWORD WINAPI ThreadProc( LPVOID lpParam )<br />{<br /> HANDLE hStdout;<br /> PMYDATA pData;</p><p> TCHAR msgBuf[BUF_SIZE];<br /> size_t cchStringSize;<br /> DWORD dwChars;</p><p> hStdout = GetStdHandle(STD_OUTPUT_HANDLE);<br /> if( hStdout == INVALID_HANDLE_VALUE )<br /> return 1;</p><p> // Cast the parameter to the correct data type.</p><p> pData = (PMYDATA)lpParam;</p><p> // Print the parameter values using thread-safe functions.</p><p> StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d/n"),<br /> pData->val1, pData->val2);<br /> StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);<br /> WriteConsole(hStdout, msgBuf, cchStringSize, &dwChars, NULL);</p><p> // Free the memory allocated by the caller for the thread<br /> // data structure.</p><p> HeapFree(GetProcessHeap(), 0, pData);</p><p> return 0;<br />} </p><p>void main()<br />{<br /> PMYDATA pData;<br /> DWORD dwThreadId[MAX_THREADS];<br /> HANDLE hThread[MAX_THREADS];<br /> int i;</p><p> // Create MAX_THREADS worker threads.</p><p> for( i=0; i<MAX_THREADS; i++ )<br /> {<br /> // Allocate memory for thread data.</p><p> pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,<br /> sizeof(MYDATA));</p><p> if( pData == NULL )<br /> ExitProcess(2);</p><p> // Generate unique data for each thread.</p><p> pData->val1 = i;<br /> pData->val2 = i+100;</p><p> hThread[i] = CreateThread(<br /> NULL, // default security attributes<br /> 0, // use default stack size<br /> ThreadProc, // thread function<br /> pData, // argument to thread function<br /> 0, // use default creation flags<br /> &dwThreadId[i]); // returns the thread identifier </p><p> // Check the return value for success. </p><p> if (hThread[i] == NULL)<br /> {<br /> ExitProcess(i);<br /> }<br /> }</p><p> // Wait until all threads have terminated.</p><p> WaitForMultipleObjects(MAX_THREADS, hThread, TRUE, INFINITE);</p><p> // Close all thread handles upon completion.</p><p> for(i=0; i<MAX_THREADS; i++)<br /> {<br /> CloseHandle(hThread[i]);<br /> }<br />}<br />