天天看點

CreateThread, AfxBeginThread,_beginthread, _beginthreadex的差別

一、轉載自: 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

// crt_BEGTHRD.C

// compile with: /MT /D "_X86_" /c

// processor: x86

#include <windows.h>

#include <process.h> /* _beginthread, _endthread */

#include <stddef.h>

#include <stdlib.h>

#include <conio.h>

void Bounce( void *ch );

void CheckKey( void *dummy );

/* GetRandom returns a random integer between min and max. */

#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

BOOL repeat = TRUE; /* Global repeat flag and video variable */

HANDLE hStdOut; /* Handle for console window */

CONSOLE_SCREEN_BUFFER_INFO csbi; /* Console information structure */

int main()

{

CHAR ch = 'A';

hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

/* Get display screen's text row and column information. */

GetConsoleScreenBufferInfo( hStdOut, &csbi );

/* Launch CheckKey thread to check for terminating keystroke. */

_beginthread( CheckKey, 0, NULL );

/* Loop until CheckKey terminates program. */

while( repeat )

{

/* On first loops, launch character threads. */

_beginthread( Bounce, 0, (void *) (ch++) );

/* Wait one second between loops. */

Sleep( 1000L );

}

}

/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */

void CheckKey( void *dummy )

{

_getch();

repeat = 0; /* _endthread implied */

}

/* Bounce - Thread to create and and control a colored letter that moves

* around on the screen.

*

* Params: ch - the letter to be moved

*/

void Bounce( void *ch )

{

/* Generate letter and color attribute from thread argument. */

char blankcell = 0x20;

char blockcell = (char) ch;

BOOL first = TRUE;

COORD oldcoord, newcoord;

DWORD result;

/* Seed random number generator and get initial location. */

srand( _threadid );

newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );

newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );

while( repeat )

{

/* Pause between loops. */

Sleep( 100L );

/* Blank out our old position on the screen, and draw new letter. */

if( first )

first = FALSE;

else

WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );

WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );

/* Increment the coordinate for next placement of the block. */

oldcoord.X = newcoord.X;

oldcoord.Y = newcoord.Y;

newcoord.X += GetRandom( -1, 1 );

newcoord.Y += GetRandom( -1, 1 );

/* Correct placement (and beep) if about to go off the screen. */

if( newcoord.X < 0 )

newcoord.X = 1;

else if( newcoord.X == csbi.dwSize.X )

newcoord.X = csbi.dwSize.X - 2;

else if( newcoord.Y < 0 )

newcoord.Y = 1;

else if( newcoord.Y == csbi.dwSize.Y )

newcoord.Y = csbi.dwSize.Y - 2;

/* If not at a screen border, continue, otherwise beep. */

else

continue;

Beep( ((char) ch - 'A') * 100, 175 );

}

/* _endthread given to terminate */

_endthread();

}

/*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.*/

// crt_begthrdex.cpp

// compile with: /MT

#include <windows.h>

#include <stdio.h>

#include <process.h>

unsigned Counter;

unsigned __stdcall SecondThreadFunc( void* pArguments )

{

printf( "In second thread.../n" );

while ( Counter < 1000000 )

Counter++;

_endthreadex( 0 );

return 0;

}

int main()

{

HANDLE hThread;

unsigned threadID;

printf( "Creating second thread.../n" );

// Create the second thread.

hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );

// Wait until second thread terminates. If you comment out the line

// below, Counter will not be correct because the thread has not

// terminated, and Counter most likely has not been incremented to

// 1000000 yet.

WaitForSingleObject( hThread, INFINITE );

printf( "Counter should be 1000000; it is-> %d/n", Counter );

// Destroy the thread object.

CloseHandle( hThread );

}

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.

/*

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.

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.*/

#include <windows.h>

#include <strsafe.h>

#define MAX_THREADS 3

#define BUF_SIZE 255

typedef struct _MyData {

int val1;

int val2;

} MYDATA, *PMYDATA;

DWORD WINAPI ThreadProc( LPVOID lpParam )

{

HANDLE hStdout;

PMYDATA pData;

TCHAR msgBuf[BUF_SIZE];

size_t cchStringSize;

DWORD dwChars;

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

if( hStdout == INVALID_HANDLE_VALUE )

return 1;

// Cast the parameter to the correct data type.

pData = (PMYDATA)lpParam;

// Print the parameter values using thread-safe functions.

StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d/n"),

pData->val1, pData->val2);

StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);

WriteConsole(hStdout, msgBuf, cchStringSize, &dwChars, NULL);

// Free the memory allocated by the caller for the thread

// data structure.

HeapFree(GetProcessHeap(), 0, pData);

return 0;

}

void main()

{

PMYDATA pData;

DWORD dwThreadId[MAX_THREADS];

HANDLE hThread[MAX_THREADS];

int i;

// Create MAX_THREADS worker threads.

for( i=0; i<MAX_THREADS; i++ )

{

// Allocate memory for thread data.

pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,

sizeof(MYDATA));

if( pData == NULL )

ExitProcess(2);

// Generate unique data for each thread.

pData->val1 = i;

pData->val2 = i+100;

hThread[i] = CreateThread(

NULL, // default security attributes

0, // use default stack size

ThreadProc, // thread function

pData, // argument to thread function

0, // use default creation flags

&dwThreadId[i]); // returns the thread identifier

// Check the return value for success.

if (hThread[i] == NULL)

{

ExitProcess(i);

}

}

// Wait until all threads have terminated.

WaitForMultipleObjects(MAX_THREADS, hThread, TRUE, INFINITE);

// Close all thread handles upon completion.

for(i=0; i<MAX_THREADS; i++)

{

CloseHandle(hThread[i]);

}

}

繼續閱讀